Arbitrary shirt, pants, glove colors + settings menu (#145)

* Support for more granular player colors

You can now configure RGB values for shirt, pants, gloves, and shoes.
Due to some limitations, configuring shoes does nothing at the moment.

* Remove paletteIndex and friends

Restructured and filled in some remaining code to account for that.

* Add Edit Palette panel to Player panel

* Change PlayerPalette contents to an enum-indexed array, remove shoes

This gets rid of all the hokey code doing switch cases on the
different parts.

* Fix goof with player model selection box

Should actually have affect now even if a custom palette is being used.

* Fix gap in player color display list commands

The extra space was leftover from when I was trying to get shoes
working. Forgot to clean it up.

* Standardize PlayerParts enum, including for lua constants autogen

* djui_panel_player.c: Properly hook sending palette changes on unpause

Editing the palette and then unpausing should send out the packet to
everyone with the new palette changes (and update the palette preset
selection box), but since we weren't hooking that situation before, it
would stay changed only for you. You would have had to press the Back
button for it to work right.

* Allow Lua mods to continue using `paletteIndex`, `overridePaletteIndex`

This lets mod code like this still work unchanged:

if s.team == 2 then
    np.overridePaletteIndex = 7
elseif s.team == 1 then
    np.overridePaletteIndex = 15
else
    np.overridePaletteIndex = np.paletteIndex
end

It's essentially faked, and would work strangely if the value of either
variable was inspected more closely directly. This should at least
handle the typical use case, though.

Every frame, `overridePaletteIndex` is checked to see if it was modified
from its previous value. If so, `overridePalette` is set to the preset
corresponding to the index. `paletteIndex` contains a special value that
when used to assign to `overridePaletteIndex`, it copies `palette` into
`overridePalette` to restore the real colors, which of course may not
follow the presets at all.

* characters.h: Pack `PlayerPalette` to eliminate size differences between computers

* mario_misc.c: Remove remaining "TODO GAG"
This commit is contained in:
TheGag96 2022-08-07 17:13:19 -05:00 committed by GitHub
parent da5cf8230b
commit dc3ca7c76d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 544 additions and 231 deletions

View File

@ -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(),
};

View File

@ -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(),
};

View File

@ -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),

View File

@ -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(),
};

View File

@ -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(),
};

View File

@ -64,7 +64,11 @@ override_field_types = {
}
override_field_mutable = {
"NetworkPlayer": [ "overrideModelIndex", "overridePaletteIndex" ],
"NetworkPlayer": [
"overrideModelIndex",
"overridePalette",
"overridePaletteIndex",
],
}
override_field_invisible = {

View File

@ -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

View File

@ -37,6 +37,12 @@ gLevelValues = {}
--- @type BehaviorValues
gBehaviorValues = {}
--- @type BehaviorValues
gBehaviorValues = {}
--- @type PlayerPalette[]
gPalettePresets = {}
-----------
-- hooks --
-----------

View File

@ -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

View File

@ -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 @@
<br />
## [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:](#)
<br />
@ -1565,6 +1574,7 @@
- UNKNOWN_GLOBAL_INDEX
- UNKNOWN_LOCAL_INDEX
- UNKNOWN_NETWORK_INDEX
- USE_REAL_PALETTE_VAR
### [enum NetworkPlayerType](#NetworkPlayerType)
| Identifier | Value |

View File

@ -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 @@
<br />
## [PlayerPalette](#PlayerPalette)
| Field | Type | Access |
| ----- | ---- | ------ |
[:arrow_up_small:](#)
<br />
## [RayIntersectionInfo](#RayIntersectionInfo)
| Field | Type | Access |

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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++);

View File

@ -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);

View File

@ -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);

View File

@ -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
}

View File

@ -2,6 +2,8 @@
#define CONFIGFILE_H
#include <stdbool.h>
#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;

View File

@ -1,10 +1,185 @@
#include <stdio.h>
#include <stdlib.h>
#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);

View File

@ -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++) {

View File

@ -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);
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);

View File

@ -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;

View File

@ -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);

View File

@ -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 },

View File

@ -51,6 +51,7 @@ enum LuaObjectAutogenType {
LOT_PARALLELTRACKINGPOINT,
LOT_PLAYERCAMERASTATE,
LOT_PLAYERGEOMETRY,
LOT_PLAYERPALETTE,
LOT_RAYINTERSECTIONINFO,
LOT_SERVERSETTINGS,
LOT_SOUNDSTATE,

View File

@ -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"

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;