diff --git a/actors/luigi/model.inc.c b/actors/luigi/model.inc.c index 79ecfcee..57a77375 100644 --- a/actors/luigi/model.inc.c +++ b/actors/luigi/model.inc.c @@ -473,8 +473,8 @@ const Gfx luigi_left_hand_closed_shared_dl[] = { }; const Gfx luigi_left_hand_closed[] = { - gsSPLight(&luigi_white_lights_group.l, 1), - gsSPLight(&luigi_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(luigi_left_hand_closed_shared_dl), gsSPEndDisplayList(), }; @@ -711,8 +711,8 @@ const Gfx luigi_right_hand_closed_dl[] = { }; const Gfx luigi_right_hand_closed[] = { - gsSPLight(&luigi_white_lights_group.l, 1), - gsSPLight(&luigi_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(luigi_right_hand_closed_dl), gsSPEndDisplayList(), }; @@ -3049,8 +3049,8 @@ const Gfx luigi_left_hand_open_shared_dl[] = { }; const Gfx luigi_left_hand_open[] = { - gsSPLight(&luigi_white_lights_group.l, 1), - gsSPLight(&luigi_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(luigi_left_hand_open_shared_dl), gsSPEndDisplayList(), }; @@ -3191,8 +3191,8 @@ const Gfx luigi_right_hand_open_dl[] = { }; const Gfx luigi_right_hand_open[] = { - gsSPLight(&luigi_white_lights_group.l, 1), - gsSPLight(&luigi_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(luigi_right_hand_open_dl), gsSPEndDisplayList(), }; @@ -3446,8 +3446,8 @@ const Gfx luigi_right_hand_cap_bottom_dl[] = { const Gfx luigi_right_hand_cap_dl[] = { gsSPDisplayList(luigi_right_hand_cap_top_dl), - gsSPLight(&luigi_white_lights_group.l, 1), - gsSPLight(&luigi_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(luigi_right_hand_cap_hand_position_dl), gsSPLight(&luigi_brown2_lights_group.l, 1), gsSPLight(&luigi_brown2_lights_group.a, 2), @@ -3751,8 +3751,8 @@ const Gfx luigi_right_hand_peace_shared_dl[] = { }; const Gfx luigi_right_hand_peace[] = { - gsSPLight(&luigi_white_lights_group.l, 1), - gsSPLight(&luigi_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(luigi_right_hand_peace_shared_dl), gsSPEndDisplayList(), }; diff --git a/actors/mario/model.inc.c b/actors/mario/model.inc.c index 1611c1e6..7c963fd9 100644 --- a/actors/mario/model.inc.c +++ b/actors/mario/model.inc.c @@ -651,8 +651,8 @@ const Gfx mario_left_hand_closed_shared_dl[] = { // 0x0400D8F0 - 0x0400D910 const Gfx mario_left_hand_closed[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_left_hand_closed_shared_dl), gsSPEndDisplayList(), }; @@ -897,8 +897,8 @@ const Gfx mario_right_hand_closed_dl[] = { // 0x0400E458 - 0x0400E478 const Gfx mario_right_hand_closed[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_right_hand_closed_dl), gsSPEndDisplayList(), }; @@ -3444,8 +3444,8 @@ const Gfx mario_medium_poly_left_hand_closed_shared_dl[] = { // 0x04014DC0 - 0x04014DE0 const Gfx mario_medium_poly_left_hand_closed[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPLight(&mario_white_lights_group.l, 7), + gsSPLight(&mario_white_lights_group.a, 8), gsSPDisplayList(mario_medium_poly_left_hand_closed_shared_dl), gsSPEndDisplayList(), }; @@ -3483,8 +3483,8 @@ const Gfx mario_medium_poly_right_arm_shared_dl[] = { // 0x04014F40 - 0x04014F60 const Gfx mario_medium_poly_right_arm[] = { - gsSPCopyLightEXT(1, 5), // gsSPLight(&mario_red_lights_group.l, 1), - gsSPCopyLightEXT(2, 6), // gsSPLight(&mario_red_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // gsSPLight(&mario_red_lights_group.l, 1), + gsSPCopyLightEXT(2, 8), // gsSPLight(&mario_red_lights_group.a, 2), gsSPDisplayList(mario_medium_poly_right_arm_shared_dl), gsSPEndDisplayList(), }; @@ -3606,8 +3606,8 @@ const Gfx mario_medium_poly_right_hand_closed_dl[] = { // 0x040154E0 - 0x04015500 const Gfx mario_medium_poly_right_hand_closed[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_medium_poly_right_hand_closed_dl), gsSPEndDisplayList(), }; @@ -4253,8 +4253,8 @@ const Gfx mario_low_poly_left_hand_closed_shared_dl[] = { // 0x04016E80 - 0x04016EA0 const Gfx mario_low_poly_left_hand_closed[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_low_poly_left_hand_closed_shared_dl), gsSPEndDisplayList(), }; @@ -4344,8 +4344,8 @@ const Gfx mario_low_poly_right_hand_closed_dl[] = { // 0x040171C0 - 0x040171E0 const Gfx mario_low_poly_right_hand_closed[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_low_poly_right_hand_closed_dl), gsSPEndDisplayList(), }; @@ -5599,8 +5599,8 @@ const Gfx mario_left_hand_open_shared_dl[] = { // 0x04019CA0 - 0x04019CC0 const Gfx mario_left_hand_open[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_left_hand_open_shared_dl), gsSPEndDisplayList(), }; @@ -5758,8 +5758,8 @@ const Gfx mario_right_hand_open_dl[] = { // 0x0401A428 - 0x0401A448 const Gfx mario_right_hand_open[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_right_hand_open_dl), gsSPEndDisplayList(), }; @@ -6008,8 +6008,8 @@ const Gfx mario_right_hand_cap_bottom_dl[] = { // 0x0401AF20 - 0x0401AF60 const Gfx mario_right_hand_cap_dl[] = { gsSPDisplayList(mario_right_hand_cap_top_dl), - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_right_hand_cap_hand_position_dl), gsSPLight(&mario_brown2_lights_group.l, 1), gsSPLight(&mario_brown2_lights_group.a, 2), @@ -6401,8 +6401,8 @@ const Gfx mario_right_hand_peace_shared_dl[] = { // 0x0401BF30 - 0x0401BF50 const Gfx mario_right_hand_peace[] = { - gsSPLight(&mario_white_lights_group.l, 1), - gsSPLight(&mario_white_lights_group.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(mario_right_hand_peace_shared_dl), gsSPEndDisplayList(), }; diff --git a/actors/toad_player/model.inc.c b/actors/toad_player/model.inc.c index e77ae8d1..650202ff 100644 --- a/actors/toad_player/model.inc.c +++ b/actors/toad_player/model.inc.c @@ -807,8 +807,8 @@ const Gfx toad_player_dl_cap[] = { gsDPPipeSync(), gsDPSetCombineMode(G_CC_SHADEFADEA, G_CC_SHADEFADEA), - gsSPLight(&toad_player_lights_cap.l, 1), - gsSPLight(&toad_player_lights_cap.a, 2), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPDisplayList(toad_player_dl_cap_inner), diff --git a/actors/waluigi/model.inc.c b/actors/waluigi/model.inc.c index 6ef26af7..28904216 100644 --- a/actors/waluigi/model.inc.c +++ b/actors/waluigi/model.inc.c @@ -3687,7 +3687,8 @@ Gfx mat_waluigi_gloves_v3[] = { gsDPPipeSync(), gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, 0, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0), gsDPSetTileSize(0, 0, 0, 124, 124), - gsSPSetLights1(waluigi_gloves_v3_lights), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPEndDisplayList(), }; diff --git a/actors/wario/model.inc.c b/actors/wario/model.inc.c index 63bdbddb..b88e31ea 100644 --- a/actors/wario/model.inc.c +++ b/actors/wario/model.inc.c @@ -3670,7 +3670,8 @@ Gfx mat_wario_gloves[] = { gsDPPipeSync(), gsDPSetCombineLERP(0, 0, 0, SHADE, 0, 0, 0, ENVIRONMENT, 0, 0, 0, SHADE, 0, 0, 0, ENVIRONMENT), gsSPTexture(65535, 65535, 0, 0, 1), - gsSPSetLights1(wario_white_lights_group), + gsSPCopyLightEXT(1, 7), // glove light, set in mario_misc.c + gsSPCopyLightEXT(2, 8), gsSPEndDisplayList(), }; diff --git a/autogen/convert_structs.py b/autogen/convert_structs.py index ef36c8e4..ca82153e 100644 --- a/autogen/convert_structs.py +++ b/autogen/convert_structs.py @@ -64,7 +64,11 @@ override_field_types = { } override_field_mutable = { - "NetworkPlayer": [ "overrideModelIndex", "overridePaletteIndex" ], + "NetworkPlayer": [ + "overrideModelIndex", + "overridePalette", + "overridePaletteIndex", + ], } override_field_invisible = { diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 502c2da6..27060d20 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -2523,7 +2523,7 @@ SHAKE_SHOCK = 10 SHAKE_SMALL_DAMAGE = 3 --- @type integer -PALETTE_MAX = 32 +PALETTE_PRESET_MAX = 32 --- @class CharacterSound @@ -2682,6 +2682,20 @@ CT_WARIO = 4 --- @type CharacterType CT_MAX = 5 +--- @class PlayerParts + +--- @type PlayerParts +SHIRT = 0 + +--- @type PlayerParts +PANTS = 1 + +--- @type PlayerParts +GLOVES = 2 + +--- @type PlayerParts +PLAYER_PART_MAX = 3 + --- @class DialogId --- @type DialogId @@ -4460,6 +4474,9 @@ UNKNOWN_LOCAL_INDEX = (-1) --- @type integer UNKNOWN_NETWORK_INDEX = (-1) +--- @type integer +USE_REAL_PALETTE_VAR = 0xFF + --- @class NetworkPlayerType --- @type NetworkPlayerType diff --git a/autogen/lua_definitions/manual.lua b/autogen/lua_definitions/manual.lua index 023337d9..d5e4e35a 100644 --- a/autogen/lua_definitions/manual.lua +++ b/autogen/lua_definitions/manual.lua @@ -37,6 +37,12 @@ gLevelValues = {} --- @type BehaviorValues gBehaviorValues = {} +--- @type BehaviorValues +gBehaviorValues = {} + +--- @type PlayerPalette[] +gPalettePresets = {} + ----------- -- hooks -- ----------- diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 362e7bc0..eac25574 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -786,7 +786,10 @@ --- @field public name string --- @field public onRxSeqId integer --- @field public overrideModelIndex integer +--- @field public overridePalette PlayerPalette --- @field public overridePaletteIndex integer +--- @field public overridePaletteIndexLp integer +--- @field public palette PlayerPalette --- @field public paletteIndex integer --- @field public type integer @@ -1602,6 +1605,8 @@ --- @field public prevFloorType integer --- @field public waterHeight number +--- @class PlayerPalette + --- @class RayIntersectionInfo --- @field public hitPos Vec3f --- @field public surface Surface diff --git a/docs/lua/constants.md b/docs/lua/constants.md index b42f7175..a5188c0b 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -8,6 +8,7 @@ - [characters.h](#charactersh) - [enum CharacterSound](#enum-CharacterSound) - [enum CharacterType](#enum-CharacterType) + - [enum PlayerParts](#enum-PlayerParts) - [dialog_ids.h](#dialog_idsh) - [enum DialogId](#enum-DialogId) - [djui_hud_utils.h](#djui_hud_utilsh) @@ -809,7 +810,7 @@
## [characters.h](#characters.h) -- PALETTE_MAX +- PALETTE_PRESET_MAX ### [enum CharacterSound](#CharacterSound) | Identifier | Value | @@ -870,6 +871,14 @@ | CT_WARIO | 4 | | CT_MAX | 5 | +### [enum PlayerParts](#PlayerParts) +| Identifier | Value | +| :--------- | :---- | +| SHIRT | 0 | +| PANTS | 1 | +| GLOVES | 2 | +| PLAYER_PART_MAX | 3 | + [:arrow_up_small:](#)
@@ -1565,6 +1574,7 @@ - UNKNOWN_GLOBAL_INDEX - UNKNOWN_LOCAL_INDEX - UNKNOWN_NETWORK_INDEX +- USE_REAL_PALETTE_VAR ### [enum NetworkPlayerType](#NetworkPlayerType) | Identifier | Value | diff --git a/docs/lua/structs.md b/docs/lua/structs.md index 3647c654..f76135da 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -48,6 +48,7 @@ - [ParallelTrackingPoint](#ParallelTrackingPoint) - [PlayerCameraState](#PlayerCameraState) - [PlayerGeometry](#PlayerGeometry) +- [PlayerPalette](#PlayerPalette) - [RayIntersectionInfo](#RayIntersectionInfo) - [SPTask](#SPTask) - [ServerSettings](#ServerSettings) @@ -1123,7 +1124,10 @@ | name | `string` | read-only | | onRxSeqId | `integer` | read-only | | overrideModelIndex | `integer` | | +| overridePalette | [PlayerPalette](structs.md#PlayerPalette) | | | overridePaletteIndex | `integer` | | +| overridePaletteIndexLp | `integer` | read-only | +| palette | [PlayerPalette](structs.md#PlayerPalette) | read-only | | paletteIndex | `integer` | read-only | | type | `integer` | read-only | @@ -2007,6 +2011,15 @@
+## [PlayerPalette](#PlayerPalette) + +| Field | Type | Access | +| ----- | ---- | ------ | + +[:arrow_up_small:](#) + +
+ ## [RayIntersectionInfo](#RayIntersectionInfo) | Field | Type | Access | diff --git a/mods/arena/arena-player.lua b/mods/arena/arena-player.lua index 9ace5ce9..815d0ef4 100644 --- a/mods/arena/arena-player.lua +++ b/mods/arena/arena-player.lua @@ -372,11 +372,11 @@ function mario_update(m) -- update palette if s.team == 2 then - np.overridePaletteIndex = 7 + np.overridePalette = gPalettePresets[7] elseif s.team == 1 then - np.overridePaletteIndex = 15 + np.overridePalette = gPalettePresets[15] else - np.overridePaletteIndex = np.paletteIndex + np.overridePalette = np.palette end -- set metal diff --git a/mods/football.lua b/mods/football.lua index 29aca154..61030f8d 100644 --- a/mods/football.lua +++ b/mods/football.lua @@ -1262,13 +1262,13 @@ function mario_update(m) local s = gPlayerSyncTable[m.playerIndex] local np = gNetworkPlayers[m.playerIndex] if s.team == 2 then - np.overridePaletteIndex = 7 + np.overridePalette = gPalettePresets[7] m.marioBodyState.modelState = 0 elseif s.team == 1 then - np.overridePaletteIndex = 15 + np.overridePalette = gPalettePresets[15] m.marioBodyState.modelState = 0 else - np.overridePaletteIndex = np.paletteIndex + np.overridePalette = np.palette m.marioBodyState.modelState = MODEL_STATE_NOISE_ALPHA end m.health = 0x880 diff --git a/src/game/characters.c b/src/game/characters.c index 96025af9..66bd6d74 100644 --- a/src/game/characters.c +++ b/src/game/characters.c @@ -355,6 +355,55 @@ struct Character gCharacters[CT_MAX] = { }, }; +const struct PlayerPalette DEFAULT_MARIO_PALETTE = {{{0xff, 0x00, 0x00}, {0x00, 0x00, 0xff}, {0xff, 0xff, 0xff}}}; + +const struct PlayerPalette gPalettePresets[PALETTE_PRESET_MAX] = { + //shirt //pants //gloves + + // default mario + {{{0xff, 0x00, 0x00}, {0x00, 0x00, 0xff}, {0xff, 0xff, 0xff}}}, + // default luigi + {{{0x00, 0x98, 0x00}, {0x00, 0x00, 0xfe}, {0xff, 0xff, 0xff}}}, + // fake waluigi + {{{0x6d, 0x3c, 0x9a}, {0x2c, 0x26, 0x3f}, {0xff, 0xff, 0xff}}}, + // fake wario + {{{0xf9, 0xeb, 0x30}, {0x7f, 0x20, 0x7a}, {0xff, 0xff, 0xff}}}, + + {{{0x7b, 0x00, 0xde}, {0xff, 0x00, 0x00}, {0xff, 0xff, 0xff}}}, + {{{0x95, 0x43, 0x01}, {0xc6, 0xb1, 0x32}, {0xff, 0xff, 0xff}}}, + {{{0x4c, 0x5f, 0x20}, {0x07, 0x09, 0x07}, {0xff, 0xff, 0xff}}}, + {{{0x00, 0x2f, 0xc8}, {0xbf, 0xde, 0xff}, {0xff, 0xff, 0xff}}}, + {{{0x11, 0x11, 0x11}, {0xf8, 0x3b, 0x05}, {0xff, 0xff, 0xff}}}, + {{{0xc1, 0x2c, 0x72}, {0x34, 0x16, 0x0d}, {0xff, 0xff, 0xff}}}, + {{{0xff, 0x96, 0xc8}, {0xff, 0x00, 0x00}, {0xff, 0xff, 0xff}}}, + {{{0x4c, 0xff, 0x4c}, {0x81, 0x00, 0x00}, {0xff, 0xff, 0xff}}}, + {{{0xa9, 0x78, 0xfc}, {0x61, 0x3d, 0x2e}, {0xff, 0xff, 0xff}}}, + + {{{0x84, 0x60, 0x00}, {0x00, 0x46, 0x5c}, {0xff, 0xff, 0xff}}}, + {{{0x5a, 0x94, 0xff}, {0x4f, 0x31, 0x8b}, {0xff, 0xff, 0xff}}}, + {{{0x68, 0x0a, 0x17}, {0x23, 0x11, 0x03}, {0xff, 0xff, 0xff}}}, + {{{0x95, 0xd0, 0x8f}, {0x53, 0x39, 0x3d}, {0xff, 0xff, 0xff}}}, + + {{{0x37, 0x32, 0x42}, {0xe6, 0xe3, 0xff}, {0xff, 0xff, 0xff}}}, + {{{0xff, 0x8a, 0x00}, {0x00, 0x51, 0x10}, {0xff, 0xff, 0xff}}}, + {{{0x65, 0xfa, 0xff}, {0x4c, 0x1e, 0x3f}, {0xff, 0xff, 0xff}}}, + + {{{0xe6, 0xe6, 0xe6}, {0xb2, 0x28, 0x18}, {0xff, 0xff, 0xff}}}, + {{{0xe6, 0xe6, 0xe6}, {0x00, 0x98, 0x00}, {0xff, 0xff, 0xff}}}, + {{{0xe6, 0xe6, 0xe6}, {0x6d, 0x3c, 0x9a}, {0xff, 0xff, 0xff}}}, + {{{0xe6, 0xe6, 0xe6}, {0xf9, 0xeb, 0x30}, {0xff, 0xff, 0xff}}}, + + {{{0xe7, 0xe7, 0x21}, {0x17, 0x18, 0x15}, {0xff, 0xff, 0xff}}}, + {{{0xaa, 0x27, 0x31}, {0xf7, 0x9a, 0x47}, {0xff, 0xff, 0xff}}}, + {{{0x55, 0x92, 0xb2}, {0xf7, 0xc2, 0x45}, {0xff, 0xff, 0xff}}}, + {{{0x10, 0x1b, 0x2e}, {0xeb, 0x8a, 0x4b}, {0xff, 0xff, 0xff}}}, + {{{0x3b, 0x8f, 0xf7}, {0xd6, 0x35, 0x4d}, {0xff, 0xff, 0xff}}}, + {{{0xff, 0x8e, 0xb2}, {0xd6, 0x35, 0x4d}, {0xff, 0xff, 0xff}}}, + + {{{0x47, 0xc5, 0xff}, {0xb2, 0x28, 0x18}, {0xff, 0xff, 0xff}}}, + {{{0x47, 0xc5, 0xff}, {0x00, 0x98, 0x00}, {0xff, 0xff, 0xff}}}, +}; + enum AnimType { ANIM_TYPE_NONE, ANIM_TYPE_LOWY, diff --git a/src/game/characters.h b/src/game/characters.h index 8aaf1d5c..7757113b 100644 --- a/src/game/characters.h +++ b/src/game/characters.h @@ -2,9 +2,25 @@ #define CHARACTERS_H #include "PR/ultratypes.h" #include "types.h" +#include "pc/configfile.h" // NOTE: do not include any additional headers -#define PALETTE_MAX 32 +#define PALETTE_PRESET_MAX 32 + +enum PlayerParts { + SHIRT, PANTS, GLOVES, PLAYER_PART_MAX + //SHOES (can't implement due to light limit) +}; + +#pragma pack(1) +struct PlayerPalette { + //rgb + u8 parts[PLAYER_PART_MAX][3]; +}; +#pragma pack() + +extern const struct PlayerPalette DEFAULT_MARIO_PALETTE; +extern const struct PlayerPalette gPalettePresets[PALETTE_PRESET_MAX]; enum CharacterType { CT_MARIO, diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 854cd3c2..a00e5522 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -54,8 +54,7 @@ enum UnlockDoorStarStates { }; struct PlayerColor { - Lights1 shirt; - Lights1 pants; + Lights1 parts[PLAYER_PART_MAX]; }; /** @@ -80,58 +79,14 @@ struct MarioBodyState gBodyStates[MAX_PLAYERS]; struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; // copy of Mario's geo node for drawing mirror Mario // ambient color is always half the diffuse color, so we can pull a macro -#define DEFINE_PLAYER_COLOR(sr, sg, sb, pr, pg, pb) \ - { \ - gdSPDefLights1((sr >> 1), (sg >> 1), (sb >> 1), sr, sg, sb, 0x28, 0x28, 0x28), \ - gdSPDefLights1((pr >> 1), (pg >> 1), (pb >> 1), pr, pg, pb, 0x28, 0x28, 0x28), \ - } +#define PALETTE_TO_LIGHTS(palette) \ + {{ \ + gdSPDefLights1((palette.parts[SHIRT][0] >> 1), (palette.parts[SHIRT][1] >> 1), (palette.parts[SHIRT][2] >> 1), palette.parts[SHIRT][0], palette.parts[SHIRT][1], palette.parts[SHIRT][2], 0x28, 0x28, 0x28), \ + gdSPDefLights1((palette.parts[PANTS][0] >> 1), (palette.parts[PANTS][1] >> 1), (palette.parts[PANTS][2] >> 1), palette.parts[PANTS][0], palette.parts[PANTS][1], palette.parts[PANTS][2], 0x28, 0x28, 0x28), \ + gdSPDefLights1((palette.parts[GLOVES][0] >> 1), (palette.parts[GLOVES][1] >> 1), (palette.parts[GLOVES][2] >> 1), palette.parts[GLOVES][0], palette.parts[GLOVES][1], palette.parts[GLOVES][2], 0x28, 0x28, 0x28), \ + }} -struct PlayerColor gPlayerColors[PALETTE_MAX] = { - // default mario - DEFINE_PLAYER_COLOR(0xff, 0x00, 0x00, /**/ 0x00, 0x00, 0xff), - // default luigi - DEFINE_PLAYER_COLOR(0x00, 0x98, 0x00, /**/ 0x00, 0x00, 0xfe), - // fake waluigi - DEFINE_PLAYER_COLOR(0x6d, 0x3c, 0x9a, /**/ 0x2c, 0x26, 0x3f), - // fake wario - DEFINE_PLAYER_COLOR(0xf9, 0xeb, 0x30, /**/ 0x7f, 0x20, 0x7a), - - DEFINE_PLAYER_COLOR(0x7b, 0x00, 0xde, /**/ 0xff, 0x00, 0x00), - DEFINE_PLAYER_COLOR(0x95, 0x43, 0x01, /**/ 0xc6, 0xb1, 0x32), - DEFINE_PLAYER_COLOR(0x4c, 0x5f, 0x20, /**/ 0x07, 0x09, 0x07), - DEFINE_PLAYER_COLOR(0x00, 0x2f, 0xc8, /**/ 0xbf, 0xde, 0xff), - DEFINE_PLAYER_COLOR(0x11, 0x11, 0x11, /**/ 0xf8, 0x3b, 0x05), - DEFINE_PLAYER_COLOR(0xc1, 0x2c, 0x72, /**/ 0x34, 0x16, 0x0d), - DEFINE_PLAYER_COLOR(0xff, 0x96, 0xc8, /**/ 0xff, 0x00, 0x00), - DEFINE_PLAYER_COLOR(0x4c, 0xff, 0x4c, /**/ 0x81, 0x00, 0x00), - DEFINE_PLAYER_COLOR(0xa9, 0x78, 0xfc, /**/ 0x61, 0x3d, 0x2e), - - DEFINE_PLAYER_COLOR(0x84, 0x60, 0x00, /**/ 0x00, 0x46, 0x5c), - DEFINE_PLAYER_COLOR(0x5a, 0x94, 0xff, /**/ 0x4f, 0x31, 0x8b), - DEFINE_PLAYER_COLOR(0x68, 0x0a, 0x17, /**/ 0x23, 0x11, 0x03), - DEFINE_PLAYER_COLOR(0x95, 0xd0, 0x8f, /**/ 0x53, 0x39, 0x3d), - - DEFINE_PLAYER_COLOR(0x37, 0x32, 0x42, /**/ 0xe6, 0xe3, 0xff), - DEFINE_PLAYER_COLOR(0xff, 0x8a, 0x00, /**/ 0x00, 0x51, 0x10), - DEFINE_PLAYER_COLOR(0x65, 0xfa, 0xff, /**/ 0x4c, 0x1e, 0x3f), - - DEFINE_PLAYER_COLOR(0xe6, 0xe6, 0xe6, /**/ 0xb2, 0x28, 0x18), - DEFINE_PLAYER_COLOR(0xe6, 0xe6, 0xe6, /**/ 0x00, 0x98, 0x00), - DEFINE_PLAYER_COLOR(0xe6, 0xe6, 0xe6, /**/ 0x6d, 0x3c, 0x9a), - DEFINE_PLAYER_COLOR(0xe6, 0xe6, 0xe6, /**/ 0xf9, 0xeb, 0x30), - - DEFINE_PLAYER_COLOR(0xe7, 0xe7, 0x21, /**/ 0x17, 0x18, 0x15), - DEFINE_PLAYER_COLOR(0xaa, 0x27, 0x31, /**/ 0xf7, 0x9a, 0x47), - DEFINE_PLAYER_COLOR(0x55, 0x92, 0xb2, /**/ 0xf7, 0xc2, 0x45), - DEFINE_PLAYER_COLOR(0x10, 0x1b, 0x2e, /**/ 0xeb, 0x8a, 0x4b), - DEFINE_PLAYER_COLOR(0x3b, 0x8f, 0xf7, /**/ 0xd6, 0x35, 0x4d), - DEFINE_PLAYER_COLOR(0xff, 0x8e, 0xb2, /**/ 0xd6, 0x35, 0x4d), - - DEFINE_PLAYER_COLOR(0x47, 0xc5, 0xff, /**/ 0xb2, 0x28, 0x18), - DEFINE_PLAYER_COLOR(0x47, 0xc5, 0xff, /**/ 0x00, 0x98, 0x00), -}; - -const size_t gNumPlayerColors = sizeof(gPlayerColors) / sizeof(*gPlayerColors); +struct PlayerColor gNetworkPlayerColors[MAX_PLAYERS]; // This whole file is weirdly organized. It has to be the same file due // to rodata boundaries and function aligns, which means the programmer @@ -139,36 +94,6 @@ const size_t gNumPlayerColors = sizeof(gPlayerColors) / sizeof(*gPlayerColors); // (message NPC related things, the Mario head geo, and Mario geo // functions) -/** - * Set the Light1 struct from player colors. - * The 4th component is the shade factor (difference between ambient and diffuse), - * usually set to 1. - */ -void set_player_colors(u8 paletteIndex, const u8 shirt[4], const u8 pants[4]) { - // choose the last color in the table for extra players - if (paletteIndex >= gNumPlayerColors) paletteIndex = gNumPlayerColors - 1; - const u8 pAmb[3] = { pants[0] >> pants[3], pants[1] >> pants[3], pants[2] >> pants[3] }; - const u8 sAmb[3] = { shirt[0] >> shirt[3], shirt[1] >> shirt[3], shirt[2] >> shirt[3] }; - gPlayerColors[paletteIndex].pants = - (Lights1) gdSPDefLights1(pAmb[0], pAmb[1], pAmb[2], pants[0], pants[1], pants[2], 0x28, 0x28, 0x28); - gPlayerColors[paletteIndex].shirt = - (Lights1) gdSPDefLights1(sAmb[0], sAmb[1], sAmb[2], shirt[0], shirt[1], shirt[2], 0x28, 0x28, 0x28); -} - -/** - * Return the specified color for player globalIndex. - * 0 = shirt, 1 = pants - * Returns RGB, not RGBA! - */ -u8 *get_player_color(u8 paletteIndex, const s32 which) { - // choose the last color in the table for extra players - if (paletteIndex >= gNumPlayerColors) paletteIndex = gNumPlayerColors - 1; - if (which == 0) - return gPlayerColors[paletteIndex].shirt.l[0].l.col; - else - return gPlayerColors[paletteIndex].pants.l[0].l.col; -} - /** * Geo node script that draws Mario's head on the title screen. */ @@ -827,21 +752,26 @@ Gfx* geo_mario_set_player_colors(s32 callContext, struct GraphNode* node, UNUSED struct GraphNodeGenerated* asGenerated = (struct GraphNodeGenerated*) node; Gfx* gfx = NULL; u8 index = geo_get_processing_object_index(); - u8 colorIndex = gNetworkPlayers[index].overridePaletteIndex; + + struct PlayerColor color = PALETTE_TO_LIGHTS(gNetworkPlayers[index].overridePalette); + + gNetworkPlayerColors[index] = color; + struct MarioBodyState* bodyState = &gBodyStates[index]; if (callContext == GEO_CONTEXT_RENDER) { // extra players get last color - if (colorIndex >= gNumPlayerColors) colorIndex = gNumPlayerColors - 1; - gfx = alloc_display_list(5 * sizeof(*gfx)); + gfx = alloc_display_list(7 * sizeof(*gfx)); if (gfx == NULL) { return NULL; } - // put the player colors into lights 3, 4, 5, 6 + // put the player colors into lights 3, 4, 5, 6, 7, 8 // they will be later copied to lights 1, 2 with gsSPCopyLightEXT - gSPLight(gfx + 0, &gPlayerColors[colorIndex].pants.l, 3); - gSPLight(gfx + 1, &gPlayerColors[colorIndex].pants.a, 4); - gSPLight(gfx + 2, &gPlayerColors[colorIndex].shirt.l, 5); - gSPLight(gfx + 3, &gPlayerColors[colorIndex].shirt.a, 6); - gSPEndDisplayList(gfx + 4); + gSPLight(gfx + 0, &gNetworkPlayerColors[index].parts[PANTS].l, 3); + gSPLight(gfx + 1, &gNetworkPlayerColors[index].parts[PANTS].a, 4); + gSPLight(gfx + 2, &gNetworkPlayerColors[index].parts[SHIRT].l, 5); + gSPLight(gfx + 3, &gNetworkPlayerColors[index].parts[SHIRT].a, 6); + gSPLight(gfx + 4, &gNetworkPlayerColors[index].parts[GLOVES].l, 7); + gSPLight(gfx + 5, &gNetworkPlayerColors[index].parts[GLOVES].a, 8); + gSPEndDisplayList(gfx + 6); u32 layer = LAYER_OPAQUE; if (asGenerated->parameter == 0) { // put on transparent layer if vanish effect, opaque otherwise @@ -861,24 +791,30 @@ Gfx* geo_mario_set_player_colors(s32 callContext, struct GraphNode* node, UNUSED Gfx* geo_mario_cap_display_list(s32 callContext, struct GraphNode* node, UNUSED Mat4* c) { if (callContext != GEO_CONTEXT_RENDER) { return NULL; } u8 globalIndex = geo_get_processing_object_index(); - u8 colorIndex = gNetworkPlayers[globalIndex].overridePaletteIndex; + + struct PlayerColor color = PALETTE_TO_LIGHTS(gNetworkPlayers[globalIndex].overridePalette); + + gNetworkPlayerColors[globalIndex] = color; + u8 charIndex = gNetworkPlayers[globalIndex].overrideModelIndex; if (charIndex >= CT_MAX) { charIndex = 0; } struct Character* character = &gCharacters[charIndex]; - u8 dpLength = 5; + u8 dpLength = 7; if (character->capEnemyGfx != NULL) { dpLength++; } if (character->capEnemyDecalGfx != NULL) { dpLength++; } Gfx* gfx = alloc_display_list(dpLength * sizeof(*gfx)); if (gfx == NULL) { return NULL; } Gfx* onGfx = gfx; - // put the player colors into lights 3, 4, 5, 6 + // put the player colors into lights 3, 4, 5, 6, 7, 8 // they will be later copied to lights 1, 2 with gsSPCopyLightEXT - gSPLight(onGfx++, &gPlayerColors[colorIndex].pants.l, 3); - gSPLight(onGfx++, &gPlayerColors[colorIndex].pants.a, 4); - gSPLight(onGfx++, &gPlayerColors[colorIndex].shirt.l, 5); - gSPLight(onGfx++, &gPlayerColors[colorIndex].shirt.a, 6); + gSPLight(onGfx++, &gNetworkPlayerColors[globalIndex].parts[PANTS].l, 3); + gSPLight(onGfx++, &gNetworkPlayerColors[globalIndex].parts[PANTS].a, 4); + gSPLight(onGfx++, &gNetworkPlayerColors[globalIndex].parts[SHIRT].l, 5); + gSPLight(onGfx++, &gNetworkPlayerColors[globalIndex].parts[SHIRT].a, 6); + gSPLight(onGfx++, &gNetworkPlayerColors[globalIndex].parts[GLOVES].l, 7); + gSPLight(onGfx++, &gNetworkPlayerColors[globalIndex].parts[GLOVES].a, 8); if (character->capEnemyGfx != NULL) { gSPDisplayList(onGfx++, character->capEnemyGfx); } if (character->capEnemyDecalGfx != NULL) { gSPDisplayList(onGfx++, character->capEnemyDecalGfx); } gSPEndDisplayList(onGfx++); diff --git a/src/game/mario_misc.h b/src/game/mario_misc.h index ce1ce654..63d673ed 100644 --- a/src/game/mario_misc.h +++ b/src/game/mario_misc.h @@ -8,10 +8,6 @@ extern struct GraphNodeObject gMirrorMario[MAX_PLAYERS]; extern struct MarioBodyState gBodyStates[MAX_PLAYERS]; -extern const size_t gNumPlayerColors; - -void set_player_colors(u8 paletteIndex, const u8 shirt[4], const u8 pants[4]); -u8 *get_player_color(u8 paletteIndex, const s32 which); Gfx *geo_draw_mario_head_goddard(s32 callContext, struct GraphNode *node, Mat4 *c); void bhv_toad_message_loop(void); diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 202fb2c1..5e29f3c7 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -296,6 +296,25 @@ void bhv_mario_update(void) { particleFlags |= gMarioState->particleFlags; gCurrentObject->oMarioParticleFlags = particleFlags; + // This code is meant to preserve old Lua mods' ability to set overridePaletteIndex and paletteIndex and still work + // as they expected. USE_REAL_PALETTE_VAR is meant to help support cases where mods will do: + // np.overridePaletteIndex = np.paletteIndex + // to undo the palette override and have it still go back to the new REAL palette stored in `palette`. + { + struct NetworkPlayer *np = &gNetworkPlayers[gMarioState->playerIndex]; + + if (np->overridePaletteIndex != np->overridePaletteIndexLp) { + np->overridePaletteIndexLp = np->overridePaletteIndex; + + if (np->overridePaletteIndex == USE_REAL_PALETTE_VAR) { + np->overridePalette = np->palette; + } + else { + np->overridePalette = gPalettePresets[np->overridePaletteIndex]; + } + } + } + // Mario code updates MarioState's versions of position etc, so we need // to sync it with the Mario object copy_mario_state_to_object(gMarioState); diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 342272e3..e26ee32b 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -18,7 +18,6 @@ #include "pc/crash_handler.h" #include "pc/network/moderator_list.h" - #define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0])) enum ConfigOptionType { @@ -28,6 +27,7 @@ enum ConfigOptionType { CONFIG_TYPE_BIND, CONFIG_TYPE_STRING, CONFIG_TYPE_U64, + CONFIG_TYPE_COLOR, }; struct ConfigOption { @@ -39,6 +39,7 @@ struct ConfigOption { float* floatValue; char* stringValue; u64* u64Value; + u8 (*colorValue)[3]; }; int maxStringLength; }; @@ -132,7 +133,7 @@ unsigned int configStayInLevelAfterStar = 0; unsigned int configNetworkSystem = 0; char configPlayerName[MAX_PLAYER_STRING] = ""; unsigned int configPlayerModel = 0; -unsigned int configPlayerPalette = 0; +struct PlayerPalette configPlayerPalette = {{{0xff, 0x00, 0x00}, {0x00, 0x00, 0xff}, {0xff, 0xff, 0xff}}}; bool configUncappedFramerate = true; unsigned int configFrameLimit = 60; unsigned int configDrawDistance = 5; @@ -219,7 +220,9 @@ static const struct ConfigOption options[] = { {.name = "coop_player_knockback_strength", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerKnockbackStrength}, {.name = "coop_player_model", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerModel}, {.name = "coop_player_name", .type = CONFIG_TYPE_STRING, .stringValue = (char*)&configPlayerName, .maxStringLength = MAX_PLAYER_STRING}, - {.name = "coop_player_palette", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerPalette}, + {.name = "coop_player_palette_shirt", .type = CONFIG_TYPE_COLOR , .colorValue = &configPlayerPalette.parts[SHIRT]}, + {.name = "coop_player_palette_pants", .type = CONFIG_TYPE_COLOR , .colorValue = &configPlayerPalette.parts[PANTS]}, + {.name = "coop_player_palette_gloves", .type = CONFIG_TYPE_COLOR , .colorValue = &configPlayerPalette.parts[GLOVES]}, {.name = "coop_stay_in_level_after_star", .type = CONFIG_TYPE_UINT , .uintValue = &configStayInLevelAfterStar}, {.name = "share_lives", .type = CONFIG_TYPE_BOOL , .boolValue = &configShareLives}, {.name = "disable_popups", .type = CONFIG_TYPE_BOOL , .boolValue = &configDisablePopups}, @@ -405,6 +408,7 @@ const char *configfile_name(void) { void configfile_load(const char *filename) { fs_file_t *file; char *line; + unsigned int temp; printf("Loading configuration from '%s'\n", filename); @@ -480,6 +484,12 @@ void configfile_load(const char *filename) { case CONFIG_TYPE_U64: sscanf(tokens[1], "%llu", option->u64Value); break; + case CONFIG_TYPE_COLOR: + for (int i = 0; i < 3 && i < numTokens - 1; ++i) { + sscanf(tokens[i + 1], "%x", &temp); + (*option->colorValue)[i] = temp; + } + break; default: assert(0); // bad type } @@ -541,6 +551,9 @@ void configfile_save(const char *filename) { case CONFIG_TYPE_U64: fprintf(file, "%s %llu\n", option->name, *option->u64Value); break; + case CONFIG_TYPE_COLOR: + fprintf(file, "%s %02x %02x %02x\n", option->name, (*option->colorValue)[0], (*option->colorValue)[1], (*option->colorValue)[2]); + break; default: assert(0); // unknown type } diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 4d7f2966..b01ec11c 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -2,6 +2,8 @@ #define CONFIGFILE_H #include +#include "PR/ultratypes.h" +#include "game/characters.h" #define CONFIGFILE_DEFAULT "sm64config.txt" @@ -88,7 +90,7 @@ extern unsigned int configStayInLevelAfterStar; extern unsigned int configNetworkSystem; extern char configPlayerName[]; extern unsigned int configPlayerModel; -extern unsigned int configPlayerPalette; +extern struct PlayerPalette configPlayerPalette; extern bool configUncappedFramerate; extern unsigned int configFrameLimit; extern unsigned int configDrawDistance; diff --git a/src/pc/djui/djui_panel_player.c b/src/pc/djui/djui_panel_player.c index 2814dc6f..0d279b1f 100644 --- a/src/pc/djui/djui_panel_player.c +++ b/src/pc/djui/djui_panel_player.c @@ -1,10 +1,185 @@ #include +#include #include "djui.h" #include "pc/configfile.h" #include "pc/network/network_player.h" #include "game/level_update.h" #include "game/area.h" +#define PALETTE_CUSTOM PALETTE_PRESET_MAX + +static unsigned int sPalettePresetIndex = PALETTE_CUSTOM; +static unsigned int sCurrentPlayerPart = SHIRT; +static unsigned int sSliderChannels[3] = {0}; + +static struct DjuiSelectionbox* sPalettePresetSelection; + +static struct DjuiSelectionbox* sPartSelection; +static struct DjuiInputbox* sHexColorTextBox; +static struct DjuiSlider *sSliderR, *sSliderG, *sSliderB; + +static void djui_panel_player_edit_palette_update_hex_code_box() { + char buf[7]; + static const char digitToChar[] = "0123456789abcdef"; + + for (size_t i = 0; i < 3; i++) { + buf[2*i] = digitToChar[configPlayerPalette.parts[sCurrentPlayerPart][i] >> 4]; + buf[2*i+1] = digitToChar[configPlayerPalette.parts[sCurrentPlayerPart][i] & 0xF]; + } + + buf[6] = '\0'; + + djui_inputbox_set_text(sHexColorTextBox, buf); +} + +static void djui_panel_player_edit_palette_update_palette_display() { + if (memcmp(&gNetworkPlayers[0].overridePalette, &gNetworkPlayers[0].palette, sizeof(struct PlayerPalette)) == 0) { + gNetworkPlayers[0].overridePalette = configPlayerPalette; + } + + gNetworkPlayers[0].palette = configPlayerPalette; +} + +static void djui_panel_player_edit_palette_update_sliders() { + for (int i = 0; i < 3; i++) sSliderChannels[i] = configPlayerPalette.parts[sCurrentPlayerPart][i]; + + djui_slider_update_value(&sSliderR->base); + djui_slider_update_value(&sSliderG->base); + djui_slider_update_value(&sSliderB->base); +} + +static void djui_panel_player_edit_palette_part_changed(UNUSED struct DjuiBase* caller) { + djui_panel_player_edit_palette_update_sliders(); + djui_panel_player_edit_palette_update_hex_code_box(); +} + +static int char_to_hex_digit(char c) { + return (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10; +} + +static void djui_panel_player_edit_palette_hex_code_changed(struct DjuiBase* caller) { + struct DjuiInputbox* input = (struct DjuiInputbox*) caller; + + for (int i = 0; i < 6; i++) { + char c = input->buffer[i]; + if (c == '\0') return; // all 6 characters must be filled + + if (c >= 'A' && c <= 'Z') { + input->buffer[i] = c - 'A' + 'a'; // convert all characters to lowercase + } + + if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) return; + } + + for (int i = 0; i < 3; i++) { + configPlayerPalette.parts[sCurrentPlayerPart][i] = (char_to_hex_digit(input->buffer[2*i]) << 4) | + char_to_hex_digit(input->buffer[2*i] + 1); + } + + djui_panel_player_edit_palette_update_sliders(); + djui_panel_player_edit_palette_update_palette_display(); + sPalettePresetIndex = PALETTE_CUSTOM; +} + +static void djui_panel_player_edit_palette_slider_changed(UNUSED struct DjuiBase* caller, size_t index) { + configPlayerPalette.parts[sCurrentPlayerPart][index] = sSliderChannels[index]; + + djui_panel_player_edit_palette_update_hex_code_box(); + djui_panel_player_edit_palette_update_palette_display(); + sPalettePresetIndex = PALETTE_CUSTOM; +} + +static void djui_panel_player_edit_palette_red_changed(UNUSED struct DjuiBase* caller) { + djui_panel_player_edit_palette_slider_changed(caller, 0); +} + +static void djui_panel_player_edit_palette_green_changed(UNUSED struct DjuiBase* caller) { + djui_panel_player_edit_palette_slider_changed(caller, 1); +} + +static void djui_panel_player_edit_palette_blue_changed(UNUSED struct DjuiBase* caller) { + djui_panel_player_edit_palette_slider_changed(caller, 2); +} + +static void (*sSavedDestroy)(struct DjuiBase*); +void djui_panel_player_edit_palette_destroy(struct DjuiBase* caller) { + if (gNetworkType != NT_NONE) { + network_send_player_settings(); + } + + djui_selectionbox_update_value(&sPalettePresetSelection->base); // since editing palette values can change it + + (*sSavedDestroy)(caller); +} + +static void djui_panel_player_edit_palette_create(struct DjuiBase* caller) { + char* sPartStrings[PLAYER_PART_MAX] = { "Shirt", "Pants", "Gloves" }; + + f32 bodyHeight = 32 * 5 + 64 * 1 + 16 * 5; + + struct DjuiBase* defaultBase = NULL; + struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\P\\#1be700\\A\\#00b3ff\\L\\#ffef00\\E\\#ff0800\\T\\#1be700\\T\\#00b3ff\\E"); + + // A bit of a gross hack to send out palette changes and update the palette preset selection box on unpause AND + // pressing the Back button + sSavedDestroy = panel->base.destroy; + panel->base.destroy = djui_panel_player_edit_palette_destroy; + + struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel); + + { + sCurrentPlayerPart = SHIRT; + sPartSelection = djui_selectionbox_create(&body->base, "Part", sPartStrings, PLAYER_PART_MAX, &sCurrentPlayerPart); + djui_base_set_size_type(&sPartSelection->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&sPartSelection->base, 1.0f, 32); + djui_interactable_hook_value_change(&sPartSelection->base, djui_panel_player_edit_palette_part_changed); + + struct DjuiRect* rect1 = djui_rect_create(&body->base); + djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&rect1->base, 1.0f, 32); + djui_base_set_color(&rect1->base, 0, 0, 0, 0); + { + struct DjuiText* text1 = djui_text_create(&rect1->base, "Hex Code"); + djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_color(&text1->base, 200, 200, 200, 255); + djui_base_set_size(&text1->base, 0.485f, 64); + djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP); + + sHexColorTextBox = djui_inputbox_create(&rect1->base, 7); + djui_base_set_size_type(&sHexColorTextBox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&sHexColorTextBox->base, 0.5f, 32); + djui_base_set_alignment(&sHexColorTextBox->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP); + djui_panel_player_edit_palette_update_hex_code_box(); + djui_interactable_hook_value_change(&sHexColorTextBox->base, djui_panel_player_edit_palette_hex_code_changed); + } + + for (int i = 0; i < 3; i++) sSliderChannels[i] = configPlayerPalette.parts[SHIRT][i]; + + sSliderR = djui_slider_create(&body->base, "Red", &sSliderChannels[0], 0, 255); + djui_base_set_size_type(&sSliderR->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_interactable_hook_value_change(&sSliderR->base, djui_panel_player_edit_palette_red_changed); + djui_base_set_size(&sSliderR->base, 1.0f, 32); + + sSliderG = djui_slider_create(&body->base, "Green", &sSliderChannels[1], 0, 255); + djui_base_set_size_type(&sSliderG->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_interactable_hook_value_change(&sSliderG->base, djui_panel_player_edit_palette_green_changed); + djui_base_set_size(&sSliderG->base, 1.0f, 32); + + sSliderB = djui_slider_create(&body->base, "Blue", &sSliderChannels[2], 0, 255); + djui_base_set_size_type(&sSliderB->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_interactable_hook_value_change(&sSliderB->base, djui_panel_player_edit_palette_blue_changed); + djui_base_set_size(&sSliderB->base, 1.0f, 32); + + struct DjuiButton* button6 = djui_button_create(&body->base, "Back"); + djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&button6->base, 1.0f, 64); + djui_button_set_style(button6, 1); + djui_interactable_hook_click(&button6->base, djui_panel_menu_back); + } + + djui_panel_add(caller, &panel->base, defaultBase); +} + static bool djui_panel_player_name_valid(char* buffer) { if (buffer[0] == '\0') { return false; } while (*buffer != '\0') { @@ -39,12 +214,16 @@ static void djui_panel_player_name_on_focus_end(struct DjuiBase* caller) { } } -void djui_panel_player_value_changed(UNUSED struct DjuiBase* caller) { +static void djui_panel_player_value_changed(UNUSED struct DjuiBase* caller) { + if (sPalettePresetIndex != PALETTE_CUSTOM) { + configPlayerPalette = gPalettePresets[sPalettePresetIndex]; + djui_panel_player_edit_palette_update_palette_display(); + } + if (configPlayerModel >= CT_MAX) { configPlayerModel = 0; } - if (gNetworkPlayers[0].overrideModelIndex == gNetworkPlayers[0].modelIndex) { gNetworkPlayers[0].overrideModelIndex = configPlayerModel; } - if (gNetworkPlayers[0].overridePaletteIndex == gNetworkPlayers[0].paletteIndex) { gNetworkPlayers[0].overridePaletteIndex = configPlayerPalette; } - gNetworkPlayers[0].modelIndex = configPlayerModel; - gNetworkPlayers[0].paletteIndex = configPlayerPalette; + if (gNetworkPlayers[0].overrideModelIndex == gNetworkPlayers[0].modelIndex) { gNetworkPlayers[0].overrideModelIndex = configPlayerModel; } + + gNetworkPlayers[0].modelIndex = configPlayerModel; network_player_update_model(0); if (gNetworkType != NT_NONE) { @@ -53,7 +232,7 @@ void djui_panel_player_value_changed(UNUSED struct DjuiBase* caller) { } void djui_panel_player_create(struct DjuiBase* caller) { - f32 bodyHeight = 32 * 3 + 64 * 1 + 16 * 4; + f32 bodyHeight = 32 * 3 + 64 * 2 + 16 * 5; struct DjuiBase* defaultBase = NULL; struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\P\\#1be700\\L\\#00b3ff\\A\\#ffef00\\Y\\#ff0800\\E\\#1be700\\R"); @@ -93,7 +272,7 @@ void djui_panel_player_create(struct DjuiBase* caller) { djui_base_set_size(&selectionbox1->base, 1.0f, 32); djui_interactable_hook_value_change(&selectionbox1->base, djui_panel_player_value_changed); - char* paletteChoices[PALETTE_MAX] = { + char* paletteChoices[PALETTE_PRESET_MAX+1] = { "Mario", "Luigi", "Waluigi", @@ -126,11 +305,25 @@ void djui_panel_player_create(struct DjuiBase* caller) { "Bubblegum", "Ice Mario", "Ice Luigi", + "Custom", }; - struct DjuiSelectionbox* selectionbox2 = djui_selectionbox_create(&body->base, "Palette", paletteChoices, PALETTE_MAX, &configPlayerPalette); - djui_base_set_size_type(&selectionbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(&selectionbox2->base, 1.0f, 32); - djui_interactable_hook_value_change(&selectionbox2->base, djui_panel_player_value_changed); + + for (int i = 0; i < PALETTE_PRESET_MAX; i++) { + if (memcmp(&gNetworkPlayers[0].palette, &gPalettePresets[i], sizeof(struct PlayerPalette)) == 0) { + sPalettePresetIndex = i; + break; + } + } + + sPalettePresetSelection = djui_selectionbox_create(&body->base, "Palette Preset", paletteChoices, PALETTE_PRESET_MAX+1, &sPalettePresetIndex); + djui_base_set_size_type(&sPalettePresetSelection->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&sPalettePresetSelection->base, 1.0f, 32); + djui_interactable_hook_value_change(&sPalettePresetSelection->base, djui_panel_player_value_changed); + + struct DjuiButton* editPaletteButton = djui_button_create(&body->base, "Edit Palette"); + djui_base_set_size_type(&editPaletteButton->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&editPaletteButton->base, 1.0f, 64); + djui_interactable_hook_click(&editPaletteButton->base, djui_panel_player_edit_palette_create); struct DjuiButton* button6 = djui_button_create(&body->base, "Back"); djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); diff --git a/src/pc/djui/djui_selectionbox.c b/src/pc/djui/djui_selectionbox.c index de5dbadc..1991400f 100644 --- a/src/pc/djui/djui_selectionbox.c +++ b/src/pc/djui/djui_selectionbox.c @@ -45,18 +45,24 @@ static void djui_selectionbox_get_cursor_hover_location(struct DjuiBase* base, f *y = (rectBase->elem.y + rectBase->elem.height * 3.0f / 4.0f); } +void djui_selectionbox_update_value(struct DjuiBase* base) { + struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base; + djui_text_set_text(selectionbox->rectText, selectionbox->choices[*selectionbox->value]); +} + static void djui_selectionbox_on_cursor_down_begin(struct DjuiBase* base, UNUSED bool inputCursor) { struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base; f32 x = selectionbox->rect->base.elem.x; if (gCursorX >= x) { *selectionbox->value = (*selectionbox->value + 1) % selectionbox->choiceCount; - djui_text_set_text(selectionbox->rectText, selectionbox->choices[*selectionbox->value]); + djui_selectionbox_update_value(base); if (base != NULL && base->interactable != NULL && base->interactable->on_value_change != NULL) { base->interactable->on_value_change(base); } } } + static void djui_selectionbox_destroy(struct DjuiBase* base) { struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base; for (int i = 0; i < selectionbox->choiceCount; i++) { diff --git a/src/pc/djui/djui_selectionbox.h b/src/pc/djui/djui_selectionbox.h index 736c40a8..56fdcc7b 100644 --- a/src/pc/djui/djui_selectionbox.h +++ b/src/pc/djui/djui_selectionbox.h @@ -12,4 +12,5 @@ struct DjuiSelectionbox { u8 choiceCount; }; -struct DjuiSelectionbox* djui_selectionbox_create(struct DjuiBase* parent, const char* message, char* choices[], u8 choiceCount, unsigned int* value); \ No newline at end of file +struct DjuiSelectionbox* djui_selectionbox_create(struct DjuiBase* parent, const char* message, char* choices[], u8 choiceCount, unsigned int* value); +void djui_selectionbox_update_value(struct DjuiBase* base); \ No newline at end of file diff --git a/src/pc/djui/djui_slider.c b/src/pc/djui/djui_slider.c index aec15567..d9b8a653 100644 --- a/src/pc/djui/djui_slider.c +++ b/src/pc/djui/djui_slider.c @@ -28,7 +28,7 @@ static void djui_slider_update_style(struct DjuiBase* base) { } } -static void djui_slider_update_value(struct DjuiBase* base) { +void djui_slider_update_value(struct DjuiBase* base) { struct DjuiSlider* slider = (struct DjuiSlider*)base; u32 min = slider->min; u32 max = slider->max; diff --git a/src/pc/djui/djui_slider.h b/src/pc/djui/djui_slider.h index 1c80eaee..f5da2799 100644 --- a/src/pc/djui/djui_slider.h +++ b/src/pc/djui/djui_slider.h @@ -12,3 +12,4 @@ struct DjuiSlider { }; struct DjuiSlider* djui_slider_create(struct DjuiBase* parent, const char* message, unsigned int* value, unsigned int min, unsigned int max); +void djui_slider_update_value(struct DjuiBase* base); diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index ee878116..9b4fd60e 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -891,35 +891,38 @@ static struct LuaObjectField sModeTransitionInfoFields[LUA_MODE_TRANSITION_INFO_ { "transitionStart", LVT_COBJECT, offsetof(struct ModeTransitionInfo, transitionStart), true, LOT_LINEARTRANSITIONPOINT }, }; -#define LUA_NETWORK_PLAYER_FIELD_COUNT 25 +#define LUA_NETWORK_PLAYER_FIELD_COUNT 28 static struct LuaObjectField sNetworkPlayerFields[LUA_NETWORK_PLAYER_FIELD_COUNT] = { - { "connected", LVT_BOOL, offsetof(struct NetworkPlayer, connected), true, LOT_NONE }, - { "currActNum", LVT_S16, offsetof(struct NetworkPlayer, currActNum), true, LOT_NONE }, - { "currAreaIndex", LVT_S16, offsetof(struct NetworkPlayer, currAreaIndex), true, LOT_NONE }, - { "currAreaSyncValid", LVT_BOOL, offsetof(struct NetworkPlayer, currAreaSyncValid), true, LOT_NONE }, - { "currCourseNum", LVT_S16, offsetof(struct NetworkPlayer, currCourseNum), true, LOT_NONE }, - { "currLevelAreaSeqId", LVT_U16, offsetof(struct NetworkPlayer, currLevelAreaSeqId), true, LOT_NONE }, - { "currLevelNum", LVT_S16, offsetof(struct NetworkPlayer, currLevelNum), true, LOT_NONE }, - { "currLevelSyncValid", LVT_BOOL, offsetof(struct NetworkPlayer, currLevelSyncValid), true, LOT_NONE }, - { "description", LVT_STRING, offsetof(struct NetworkPlayer, description), true, LOT_NONE }, - { "descriptionA", LVT_U8, offsetof(struct NetworkPlayer, descriptionA), true, LOT_NONE }, - { "descriptionB", LVT_U8, offsetof(struct NetworkPlayer, descriptionB), true, LOT_NONE }, - { "descriptionG", LVT_U8, offsetof(struct NetworkPlayer, descriptionG), true, LOT_NONE }, - { "descriptionR", LVT_U8, offsetof(struct NetworkPlayer, descriptionR), true, LOT_NONE }, - { "fadeOpacity", LVT_U8, offsetof(struct NetworkPlayer, fadeOpacity), true, LOT_NONE }, - { "globalIndex", LVT_U8, offsetof(struct NetworkPlayer, globalIndex), true, LOT_NONE }, - { "lastReceived", LVT_F32, offsetof(struct NetworkPlayer, lastReceived), true, LOT_NONE }, - { "lastSent", LVT_F32, offsetof(struct NetworkPlayer, lastSent), true, LOT_NONE }, - { "localIndex", LVT_U8, offsetof(struct NetworkPlayer, localIndex), true, LOT_NONE }, - { "modelIndex", LVT_U8, offsetof(struct NetworkPlayer, modelIndex), true, LOT_NONE }, - { "name", LVT_STRING, offsetof(struct NetworkPlayer, name), true, LOT_NONE }, - { "onRxSeqId", LVT_U8, offsetof(struct NetworkPlayer, onRxSeqId), true, LOT_NONE }, - { "overrideModelIndex", LVT_U8, offsetof(struct NetworkPlayer, overrideModelIndex), false, LOT_NONE }, - { "overridePaletteIndex", LVT_U8, offsetof(struct NetworkPlayer, overridePaletteIndex), false, LOT_NONE }, - { "paletteIndex", LVT_U8, offsetof(struct NetworkPlayer, paletteIndex), true, LOT_NONE }, -// { "rxPacketHash", LOT_???, offsetof(struct NetworkPlayer, rxPacketHash), true, LOT_??? }, <--- UNIMPLEMENTED -// { "rxSeqIds", LOT_???, offsetof(struct NetworkPlayer, rxSeqIds), true, LOT_??? }, <--- UNIMPLEMENTED - { "type", LVT_U8, offsetof(struct NetworkPlayer, type), true, LOT_NONE }, + { "connected", LVT_BOOL, offsetof(struct NetworkPlayer, connected), true, LOT_NONE }, + { "currActNum", LVT_S16, offsetof(struct NetworkPlayer, currActNum), true, LOT_NONE }, + { "currAreaIndex", LVT_S16, offsetof(struct NetworkPlayer, currAreaIndex), true, LOT_NONE }, + { "currAreaSyncValid", LVT_BOOL, offsetof(struct NetworkPlayer, currAreaSyncValid), true, LOT_NONE }, + { "currCourseNum", LVT_S16, offsetof(struct NetworkPlayer, currCourseNum), true, LOT_NONE }, + { "currLevelAreaSeqId", LVT_U16, offsetof(struct NetworkPlayer, currLevelAreaSeqId), true, LOT_NONE }, + { "currLevelNum", LVT_S16, offsetof(struct NetworkPlayer, currLevelNum), true, LOT_NONE }, + { "currLevelSyncValid", LVT_BOOL, offsetof(struct NetworkPlayer, currLevelSyncValid), true, LOT_NONE }, + { "description", LVT_STRING, offsetof(struct NetworkPlayer, description), true, LOT_NONE }, + { "descriptionA", LVT_U8, offsetof(struct NetworkPlayer, descriptionA), true, LOT_NONE }, + { "descriptionB", LVT_U8, offsetof(struct NetworkPlayer, descriptionB), true, LOT_NONE }, + { "descriptionG", LVT_U8, offsetof(struct NetworkPlayer, descriptionG), true, LOT_NONE }, + { "descriptionR", LVT_U8, offsetof(struct NetworkPlayer, descriptionR), true, LOT_NONE }, + { "fadeOpacity", LVT_U8, offsetof(struct NetworkPlayer, fadeOpacity), true, LOT_NONE }, + { "globalIndex", LVT_U8, offsetof(struct NetworkPlayer, globalIndex), true, LOT_NONE }, + { "lastReceived", LVT_F32, offsetof(struct NetworkPlayer, lastReceived), true, LOT_NONE }, + { "lastSent", LVT_F32, offsetof(struct NetworkPlayer, lastSent), true, LOT_NONE }, + { "localIndex", LVT_U8, offsetof(struct NetworkPlayer, localIndex), true, LOT_NONE }, + { "modelIndex", LVT_U8, offsetof(struct NetworkPlayer, modelIndex), true, LOT_NONE }, + { "name", LVT_STRING, offsetof(struct NetworkPlayer, name), true, LOT_NONE }, + { "onRxSeqId", LVT_U8, offsetof(struct NetworkPlayer, onRxSeqId), true, LOT_NONE }, + { "overrideModelIndex", LVT_U8, offsetof(struct NetworkPlayer, overrideModelIndex), false, LOT_NONE }, + { "overridePalette", LVT_COBJECT, offsetof(struct NetworkPlayer, overridePalette), false, LOT_PLAYERPALETTE }, + { "overridePaletteIndex", LVT_U8, offsetof(struct NetworkPlayer, overridePaletteIndex), false, LOT_NONE }, + { "overridePaletteIndexLp", LVT_U8, offsetof(struct NetworkPlayer, overridePaletteIndexLp), true, LOT_NONE }, + { "palette", LVT_COBJECT, offsetof(struct NetworkPlayer, palette), true, LOT_PLAYERPALETTE }, + { "paletteIndex", LVT_U8, offsetof(struct NetworkPlayer, paletteIndex), true, LOT_NONE }, +// { "rxPacketHash", LOT_???, offsetof(struct NetworkPlayer, rxPacketHash), true, LOT_??? }, <--- UNIMPLEMENTED +// { "rxSeqIds", LOT_???, offsetof(struct NetworkPlayer, rxSeqIds), true, LOT_??? }, <--- UNIMPLEMENTED + { "type", LVT_U8, offsetof(struct NetworkPlayer, type), true, LOT_NONE }, }; #define LUA_OBJECT_FIELD_COUNT 755 @@ -1762,6 +1765,11 @@ static struct LuaObjectField sPlayerGeometryFields[LUA_PLAYER_GEOMETRY_FIELD_COU { "waterHeight", LVT_F32, offsetof(struct PlayerGeometry, waterHeight), false, LOT_NONE }, }; +#define LUA_PLAYER_PALETTE_FIELD_COUNT 0 +static struct LuaObjectField sPlayerPaletteFields[LUA_PLAYER_PALETTE_FIELD_COUNT] = { +// { "parts", LOT_???, offsetof(struct PlayerPalette, parts), false, LOT_??? }, <--- UNIMPLEMENTED +}; + #define LUA_RAY_INTERSECTION_INFO_FIELD_COUNT 2 static struct LuaObjectField sRayIntersectionInfoFields[LUA_RAY_INTERSECTION_INFO_FIELD_COUNT] = { { "hitPos", LVT_COBJECT, offsetof(struct RayIntersectionInfo, hitPos), true, LOT_VEC3F }, @@ -2026,6 +2034,7 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN] { LOT_PARALLELTRACKINGPOINT, sParallelTrackingPointFields, LUA_PARALLEL_TRACKING_POINT_FIELD_COUNT }, { LOT_PLAYERCAMERASTATE, sPlayerCameraStateFields, LUA_PLAYER_CAMERA_STATE_FIELD_COUNT }, { LOT_PLAYERGEOMETRY, sPlayerGeometryFields, LUA_PLAYER_GEOMETRY_FIELD_COUNT }, + { LOT_PLAYERPALETTE, sPlayerPaletteFields, LUA_PLAYER_PALETTE_FIELD_COUNT }, { LOT_RAYINTERSECTIONINFO, sRayIntersectionInfoFields, LUA_RAY_INTERSECTION_INFO_FIELD_COUNT }, { LOT_SERVERSETTINGS, sServerSettingsFields, LUA_SERVER_SETTINGS_FIELD_COUNT }, { LOT_SOUNDSTATE, sSoundStateFields, LUA_SOUND_STATE_FIELD_COUNT }, diff --git a/src/pc/lua/smlua_cobject_autogen.h b/src/pc/lua/smlua_cobject_autogen.h index 2c93b94f..dca97d9d 100644 --- a/src/pc/lua/smlua_cobject_autogen.h +++ b/src/pc/lua/smlua_cobject_autogen.h @@ -51,6 +51,7 @@ enum LuaObjectAutogenType { LOT_PARALLELTRACKINGPOINT, LOT_PLAYERCAMERASTATE, LOT_PLAYERGEOMETRY, + LOT_PLAYERPALETTE, LOT_RAYINTERSECTIONINFO, LOT_SERVERSETTINGS, LOT_SOUNDSTATE, diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index fe87bdbb..09cf7839 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -1035,7 +1035,11 @@ char gSmluaConstants[] = "" "CAM_EVENT_START_ENDING = 11\n" "CAM_EVENT_START_END_WAVING = 12\n" "CAM_EVENT_START_CREDITS = 13\n" -"PALETTE_MAX = 32\n" +"PALETTE_PRESET_MAX = 32\n" +"SHIRT = 0\n" +"PANTS = 1\n" +"GLOVES = 2\n" +"PLAYER_PART_MAX = 3\n" "CT_MARIO = 0\n" "CT_LUIGI = 1\n" "CT_TOAD = 2\n" @@ -1671,6 +1675,7 @@ char gSmluaConstants[] = "" "UNKNOWN_NETWORK_INDEX = (-1)\n" "NETWORK_PLAYER_TIMEOUT = 10\n" "MAX_RX_SEQ_IDS = 64\n" +"USE_REAL_PALETTE_VAR = 0xFF\n" "NPT_UNKNOWN = 0\n" "NPT_LOCAL = 1\n" "NPT_SERVER = 2\n" diff --git a/src/pc/network/discord/activity.c b/src/pc/network/discord/activity.c index 0a6987f2..d7d2aa48 100644 --- a/src/pc/network/discord/activity.c +++ b/src/pc/network/discord/activity.c @@ -41,7 +41,7 @@ static void on_activity_join_callback(UNUSED void* data, enum EDiscordResult res if (gNetworkType == NT_CLIENT) { if (gNetworkPlayerServer == NULL) { - network_player_connected(NPT_SERVER, 0, 0, 0, "Player"); + network_player_connected(NPT_SERVER, 0, 0, &DEFAULT_MARIO_PALETTE, "Player"); } ns_discord_save_id(gNetworkPlayerServer->localIndex, lobby->owner_id); network_send_mod_list_request(); diff --git a/src/pc/network/network.c b/src/pc/network/network.c index dc100d45..4cdaad71 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -127,7 +127,7 @@ bool network_init(enum NetworkType inNetworkType) { dynos_behavior_hook_all_custom_behaviors(); - network_player_connected(NPT_LOCAL, 0, configPlayerModel, configPlayerPalette, configPlayerName); + network_player_connected(NPT_LOCAL, 0, configPlayerModel, &configPlayerPalette, configPlayerName); extern u8* gOverrideEeprom; gOverrideEeprom = NULL; diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index 3d3ac487..450190af 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -19,9 +19,9 @@ static char sDefaultPlayerName[] = "Player"; void network_player_init(void) { gNetworkPlayers[0].modelIndex = (configPlayerModel < CT_MAX) ? configPlayerModel : 0; - gNetworkPlayers[0].paletteIndex = configPlayerPalette; + gNetworkPlayers[0].palette = configPlayerPalette; gNetworkPlayers[0].overrideModelIndex = gNetworkPlayers[0].modelIndex; - gNetworkPlayers[0].overridePaletteIndex = gNetworkPlayers[0].paletteIndex; + gNetworkPlayers[0].overridePalette = gNetworkPlayers[0].palette; } void network_player_update_model(u8 localIndex) { @@ -169,7 +169,7 @@ void network_player_update(void) { } } -u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 modelIndex, u8 paletteIndex, char *name) { +u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 modelIndex, const struct PlayerPalette* palette, char *name) { // translate globalIndex to localIndex u8 localIndex = globalIndex; if (gNetworkType == NT_SERVER) { @@ -198,9 +198,9 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode if ((type != NPT_LOCAL) && (gNetworkType == NT_SERVER || type == NPT_SERVER)) { gNetworkSystem->save_id(localIndex, 0); } if (np->modelIndex == np->overrideModelIndex) { np->overrideModelIndex = modelIndex; } - if (np->paletteIndex == np->overridePaletteIndex) { np->overridePaletteIndex = paletteIndex; } + if (memcmp(&np->palette, &np->overridePalette, sizeof(struct PlayerPalette)) == 0) { np->overridePalette = *palette; } np->modelIndex = modelIndex; - np->paletteIndex = paletteIndex; + np->palette = *palette; network_player_update_model(localIndex); snprintf(np->name, MAX_PLAYER_STRING, "%s", name); @@ -228,9 +228,14 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode // update visuals np->fadeOpacity = 0; np->modelIndex = modelIndex; - np->paletteIndex = paletteIndex; + np->palette = *palette; np->overrideModelIndex = modelIndex; - np->overridePaletteIndex = paletteIndex; + np->overridePalette = *palette; + + np->paletteIndex = USE_REAL_PALETTE_VAR; + np->overridePaletteIndex = USE_REAL_PALETTE_VAR; + np->overridePaletteIndexLp = USE_REAL_PALETTE_VAR; + snprintf(np->name, MAX_PLAYER_STRING, "%s", name); network_player_update_model(localIndex); diff --git a/src/pc/network/network_player.h b/src/pc/network/network_player.h index 31d6da74..cb444c00 100644 --- a/src/pc/network/network_player.h +++ b/src/pc/network/network_player.h @@ -10,6 +10,7 @@ #define UNKNOWN_NETWORK_INDEX ((u64)-1) #define NETWORK_PLAYER_TIMEOUT 10 #define MAX_RX_SEQ_IDS 64 +#define USE_REAL_PALETTE_VAR 0xFF enum NetworkPlayerType { NPT_UNKNOWN, @@ -36,7 +37,7 @@ struct NetworkPlayer { u8 fadeOpacity; u8 onRxSeqId; u8 modelIndex; - u8 paletteIndex; + struct PlayerPalette palette; char name[MAX_PLAYER_STRING+1]; char description[MAX_DESCRIPTION_STRING+1]; @@ -46,10 +47,15 @@ struct NetworkPlayer { u8 descriptionA; u8 overrideModelIndex; - u8 overridePaletteIndex; + struct PlayerPalette overridePalette; u16 rxSeqIds[MAX_RX_SEQ_IDS]; u32 rxPacketHash[MAX_RX_SEQ_IDS]; + + // legacy fields to allow mods not to break + u8 paletteIndex; + u8 overridePaletteIndex; + u8 overridePaletteIndexLp; }; extern struct NetworkPlayer gNetworkPlayers[]; @@ -69,7 +75,7 @@ struct NetworkPlayer* get_network_player_smallest_global(void); void network_player_update(void); -u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 modelIndex, u8 paletteIndex, char* name); +u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 modelIndex, const struct PlayerPalette* playerPalette, char* name); u8 network_player_disconnected(u8 globalIndex); void network_player_update_course_level(struct NetworkPlayer* np, s16 courseNum, s16 actNum, s16 levelNum, s16 areaIndex); diff --git a/src/pc/network/network_utils.c b/src/pc/network/network_utils.c index 5da54f03..8e05fce7 100644 --- a/src/pc/network/network_utils.c +++ b/src/pc/network/network_utils.c @@ -30,10 +30,9 @@ u8* network_get_player_text_color(u8 localIndex) { if (localIndex >= MAX_PLAYERS) { localIndex = 0; } struct NetworkPlayer* np = &gNetworkPlayers[localIndex]; - u8* rgb = get_player_color(np->overridePaletteIndex, 0); static u8 sTextRgb[3] = { 0 }; for (int i = 0; i < 3; i++) { - sTextRgb[i] = 127 + rgb[i] / 2; + sTextRgb[i] = 127 + np->overridePalette.parts[SHIRT][i] / 2; } return sTextRgb; diff --git a/src/pc/network/packets/packet_join.c b/src/pc/network/packets/packet_join.c index cb2594d7..413a9635 100644 --- a/src/pc/network/packets/packet_join.c +++ b/src/pc/network/packets/packet_join.c @@ -26,7 +26,7 @@ extern u8* gOverrideEeprom; static u8 eeprom[512] = { 0 }; static u8 sJoinRequestPlayerModel; -static u8 sJoinRequestPlayerPalette; +static struct PlayerPalette sJoinRequestPlayerPalette; static char sJoinRequestPlayerName[MAX_PLAYER_STRING]; void network_send_join_request(void) { @@ -39,7 +39,7 @@ void network_send_join_request(void) { packet_init(&p, PACKET_JOIN_REQUEST, true, PLMT_NONE); packet_write(&p, &configPlayerModel, sizeof(u8)); - packet_write(&p, &configPlayerPalette, sizeof(u8)); + packet_write(&p, &configPlayerPalette, sizeof(struct PlayerPalette)); packet_write(&p, &configPlayerName, sizeof(u8) * MAX_PLAYER_STRING); network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p); @@ -52,11 +52,11 @@ void network_receive_join_request(struct Packet* p) { if (p->dataLength > 5) { packet_read(p, &sJoinRequestPlayerModel, sizeof(u8)); - packet_read(p, &sJoinRequestPlayerPalette, sizeof(u8)); + packet_read(p, &sJoinRequestPlayerPalette, sizeof(struct PlayerPalette)); packet_read(p, &sJoinRequestPlayerName, sizeof(u8) * MAX_PLAYER_STRING); } else { sJoinRequestPlayerModel = 0; - sJoinRequestPlayerPalette = 0; + sJoinRequestPlayerPalette = DEFAULT_MARIO_PALETTE; snprintf(sJoinRequestPlayerName, MAX_PLAYER_STRING, "%s", "Player"); } @@ -83,7 +83,7 @@ void network_send_join(struct Packet* joinRequestPacket) { LOG_INFO("chose globalIndex: %d", globalIndex); // do connection event - network_player_connected(NPT_CLIENT, globalIndex, sJoinRequestPlayerModel, sJoinRequestPlayerPalette, sJoinRequestPlayerName); + network_player_connected(NPT_CLIENT, globalIndex, sJoinRequestPlayerModel, &sJoinRequestPlayerPalette, sJoinRequestPlayerName); fs_file_t* fp = fs_open(SAVE_FILENAME); if (fp != NULL) { @@ -220,8 +220,8 @@ void network_receive_join(struct Packet* p) { } string_linked_list_free(&head); - network_player_connected(NPT_SERVER, 0, 0, 0, "Player"); - network_player_connected(NPT_LOCAL, myGlobalIndex, configPlayerModel, configPlayerPalette, configPlayerName); + network_player_connected(NPT_SERVER, 0, 0, &DEFAULT_MARIO_PALETTE, "Player"); + network_player_connected(NPT_LOCAL, myGlobalIndex, configPlayerModel, &configPlayerPalette, configPlayerName); djui_chat_box_create(); save_file_load_all(TRUE); diff --git a/src/pc/network/packets/packet_network_players.c b/src/pc/network/packets/packet_network_players.c index 607e1fce..4fc25d2e 100644 --- a/src/pc/network/packets/packet_network_players.c +++ b/src/pc/network/packets/packet_network_players.c @@ -33,7 +33,7 @@ static void network_send_to_network_players(u8 sendToLocalIndex) { packet_write(&p, &gNetworkPlayers[i].currAreaSyncValid, sizeof(u8)); packet_write(&p, &networkId, sizeof(s64)); packet_write(&p, &gNetworkPlayers[i].modelIndex, sizeof(u8)); - packet_write(&p, &gNetworkPlayers[i].paletteIndex, sizeof(u8)); + packet_write(&p, &gNetworkPlayers[i].palette, sizeof(struct PlayerPalette)); packet_write(&p, &gNetworkPlayers[i].name, sizeof(u8) * MAX_PLAYER_STRING); LOG_INFO("send network player [%d == %d]", gNetworkPlayers[i].globalIndex, npType); } @@ -89,7 +89,8 @@ void network_receive_network_players(struct Packet *p) { s16 courseNum, actNum, levelNum, areaIndex; u8 levelSyncValid, areaSyncValid; s64 networkId; - u8 modelIndex, paletteIndex; + u8 modelIndex; + struct PlayerPalette palette; char playerName[MAX_PLAYER_STRING] = { 0 }; packet_read(p, &npType, sizeof(u8)); @@ -103,10 +104,10 @@ void network_receive_network_players(struct Packet *p) { packet_read(p, &areaSyncValid, sizeof(u8)); packet_read(p, &networkId, sizeof(s64)); packet_read(p, &modelIndex, sizeof(u8)); - packet_read(p, &paletteIndex, sizeof(u8)); + packet_read(p, &palette, sizeof(struct PlayerPalette)); packet_read(p, &playerName, sizeof(u8) * MAX_PLAYER_STRING); - u8 localIndex = network_player_connected(npType, globalIndex, modelIndex, paletteIndex, playerName); + u8 localIndex = network_player_connected(npType, globalIndex, modelIndex, &palette, playerName); LOG_INFO("received network player [%d == %d] (%d)", globalIndex, npType, localIndex); if (localIndex != UNKNOWN_GLOBAL_INDEX) { struct NetworkPlayer *np = &gNetworkPlayers[localIndex]; @@ -121,7 +122,7 @@ void network_receive_network_players(struct Packet *p) { } } else { np->modelIndex = (modelIndex < CT_MAX) ? modelIndex : 0; - np->paletteIndex = paletteIndex; + np->palette = palette; network_player_update_model(localIndex); } } diff --git a/src/pc/network/packets/packet_player_settings.c b/src/pc/network/packets/packet_player_settings.c index 02d6f011..b572868a 100644 --- a/src/pc/network/packets/packet_player_settings.c +++ b/src/pc/network/packets/packet_player_settings.c @@ -13,7 +13,7 @@ void network_send_player_settings(void) { packet_write(&p, &gNetworkPlayers[0].globalIndex, sizeof(u8)); packet_write(&p, playerName, MAX_PLAYER_STRING * sizeof(u8)); packet_write(&p, &configPlayerModel, sizeof(u8)); - packet_write(&p, &configPlayerPalette, sizeof(u8)); + packet_write(&p, &configPlayerPalette, sizeof(struct PlayerPalette)); if (gNetworkPlayerLocal != NULL) { if (snprintf(gNetworkPlayerLocal->name, MAX_PLAYER_STRING, "%s", playerName) < 0) { @@ -28,12 +28,12 @@ void network_receive_player_settings(struct Packet* p) { u8 globalId; char playerName[MAX_PLAYER_STRING+1] = { 0 }; u8 playerModel; - u8 playerPalette; + struct PlayerPalette playerPalette; packet_read(p, &globalId, sizeof(u8)); packet_read(p, &playerName, MAX_PLAYER_STRING * sizeof(u8)); packet_read(p, &playerModel, sizeof(u8)); - packet_read(p, &playerPalette, sizeof(u8)); + packet_read(p, &playerPalette, sizeof(struct PlayerPalette)); if (globalId == gNetworkPlayers[0].globalIndex || globalId > MAX_PLAYERS) { LOG_ERROR("Received player settings from improper player."); @@ -48,7 +48,6 @@ void network_receive_player_settings(struct Packet* p) { // sanity check if (playerModel >= CT_MAX) { playerModel = CT_MARIO; } - if (playerPalette >= PALETTE_MAX) { playerPalette = 0; } struct NetworkPlayer* np = network_player_from_global_index(globalId); if (snprintf(np->name, MAX_PLAYER_STRING, "%s", playerName) < 0) { @@ -56,10 +55,10 @@ void network_receive_player_settings(struct Packet* p) { } if (np->modelIndex == np->overrideModelIndex) { np->overrideModelIndex = playerModel; } - if (np->paletteIndex == np->overridePaletteIndex) { np->overridePaletteIndex = playerPalette; } + if (memcmp(&np->palette, &np->overridePalette, sizeof(struct PlayerPalette)) == 0) { np->overridePalette = playerPalette; } np->modelIndex = playerModel; - np->paletteIndex = playerPalette; + np->palette = playerPalette; network_player_update_model(np->localIndex); } diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index e88f4397..ea25839b 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -316,7 +316,6 @@ void main_func(void) { dynos_pack_init(); if (configPlayerModel >= CT_MAX) { configPlayerModel = 0; } - if (configPlayerPalette >= PALETTE_MAX) { configPlayerPalette = 0; } if (gCLIOpts.FullScreen == 1) configWindow.fullscreen = true;