diff --git a/port/src/main.c b/port/src/main.c index 8573ce68e..7f4ec11ee 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -170,5 +170,6 @@ PD_CONSTRUCTOR static void gameConfigInit(void) configRegisterFloat(strFmt("Game.Player%d.CrosshairSway", i), &g_PlayerExtCfg[j].crosshairsway, 0.f, 10.f); configRegisterInt(strFmt("Game.Player%d.CrouchMode", i), &g_PlayerExtCfg[j].crouchmode, 0, CROUCHMODE_TOGGLE_ANALOG); configRegisterInt(strFmt("Game.Player%d.ExtendedControls", i), &g_PlayerExtCfg[j].extcontrols, 0, 1); + configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF); } } diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index 3a22069b9..9f3898cae 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -945,6 +945,156 @@ static MenuItemHandlerResult menuhandlerCrosshairSway(s32 operation, struct menu return 0; } +static MenuItemHandlerResult menuhandlerCrosshair_R(s32 operation, struct menuitem* item, union handlerdata* data) +{ + switch (operation) { + case MENUOP_GETSLIDER: + data->slider.value = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour >> 24) & 0xFF; + break; + + case MENUOP_SET: + u32 newColor = g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFFFFFF | data->slider.value << 24; + g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour = newColor; + break; + } + + return 0; +} + +static MenuItemHandlerResult menuhandlerCrosshair_G(s32 operation, struct menuitem* item, union handlerdata* data) +{ + switch (operation) { + case MENUOP_GETSLIDER: + data->slider.value = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour >> 16) & 0xFF; + break; + + case MENUOP_SET: + u32 newColor = g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFF00FFFF | data->slider.value << 16; + g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour = newColor; + break; + } + + return 0; +} + +static MenuItemHandlerResult menuhandlerCrosshair_B(s32 operation, struct menuitem* item, union handlerdata* data) +{ + switch (operation) { + case MENUOP_GETSLIDER: + data->slider.value = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour >> 8) & 0xFF; + break; + + case MENUOP_SET: + u32 newColor = g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFFFF00FF | data->slider.value << 8; + g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour = newColor; + break; + } + + return 0; +} + +static MenuItemHandlerResult menuhandlerCrosshair_A(s32 operation, struct menuitem* item, union handlerdata* data) +{ + switch (operation) { + case MENUOP_GETSLIDER: + data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFF; + break; + + case MENUOP_SET: + u32 newColor = g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFFFFFF00 | data->slider.value; + g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour = newColor; + break; + } + + return 0; +} + +static MenuItemHandlerResult menuhandlerCrosshairColorPreview(s32 operation, struct menuitem* item, union handlerdata* data) +{ + if (operation == MENUOP_GETCOLOUR) { + data->label.colour1 = g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour; + } + + return 0; +} + +struct menuitem g_ExtendedGameCrosshairColourMenuItems[] = { + { + MENUITEMTYPE_SLIDER, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, + (uintptr_t)"Red", + 255, + menuhandlerCrosshair_R, + }, + { + MENUITEMTYPE_SLIDER, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, + (uintptr_t)"Green", + 255, + menuhandlerCrosshair_G, + }, + { + MENUITEMTYPE_SLIDER, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, + (uintptr_t)"Blue", + 255, + menuhandlerCrosshair_B, + }, + { + MENUITEMTYPE_SLIDER, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, + (uintptr_t)"Alpha", + 255, + menuhandlerCrosshair_A, + }, + { + MENUITEMTYPE_SEPARATOR, + 0, + 0, + 0, + 0, + NULL, + }, + { + MENUITEMTYPE_COLORBOX, + 0, + 0, + 0, + 0, + menuhandlerCrosshairColorPreview, + }, + { + MENUITEMTYPE_SEPARATOR, + 0, + 0, + 0, + 0, + NULL, + }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_SELECTABLE_CLOSESDIALOG, + L_OPTIONS_213, // "Back" + 0, + NULL, + }, + { MENUITEMTYPE_END }, +}; + +struct menudialogdef g_ExtendedGameCrosshairColourMenuDialog = { + MENUDIALOGTYPE_DEFAULT, + (uintptr_t)"Crosshair Colour", + g_ExtendedGameCrosshairColourMenuItems, + NULL, + MENUDIALOGFLAG_LITERAL_TEXT, + NULL, +}; + struct menuitem g_ExtendedGameMenuItems[] = { { MENUITEMTYPE_DROPDOWN, @@ -970,6 +1120,14 @@ struct menuitem g_ExtendedGameMenuItems[] = { 20, menuhandlerCrosshairSway, }, + { + MENUITEMTYPE_SELECTABLE, + 0, + MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_OPENSDIALOG, + (uintptr_t)"Crosshair Colour\n", + 0, + (void*)&g_ExtendedGameCrosshairColourMenuDialog, + }, { MENUITEMTYPE_SEPARATOR, 0, diff --git a/src/game/menu.c b/src/game/menu.c index 6bc210525..a824b849a 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -1179,6 +1179,9 @@ bool menuIsItemFocusable(struct menuitem *item, struct menudialog *dialog, s32 a case MENUITEMTYPE_METER: case MENUITEMTYPE_MARQUEE: case MENUITEMTYPE_CONTROLLER: +#ifndef PLATFORM_N64 + case MENUITEMTYPE_COLORBOX: +#endif return false; case MENUITEMTYPE_10: case MENUITEMTYPE_14: diff --git a/src/game/menuitem.c b/src/game/menuitem.c index e42b04fbc..7f61414d9 100644 --- a/src/game/menuitem.c +++ b/src/game/menuitem.c @@ -2109,6 +2109,36 @@ Gfx *menuitemMeterRender(Gfx *gdl, struct menurendercontext *context) return gdl; } +#ifndef PLATFORM_N64 + +// Draws a colored box which fills the background of the menu item. +Gfx* menuitemColorBoxRender(Gfx *gdl, struct menurendercontext *context) +{ + u32 width = context->width; + u32 height = context->height; + u32 colour1; + s32 x1; + s32 x2; + + x1 = context->x; + x2 = x1 + width; + + union handlerdata data; + if (context->item->handlervoid) { + context->item->handlervoid(MENUOP_GETCOLOUR, context->item, &data); + } + + colour1 = data.label.colour1; + + gdl = textSetPrimColour(gdl, colour1); + gDPFillRectangleScaled(gdl++, x1, context->y, x2, context->y + height); + gdl = text0f153838(gdl); + + return gdl; +} + +#endif + Gfx *menuitemSelectableRender(Gfx *gdl, struct menurendercontext *context) { u32 leftcolour; @@ -4349,6 +4379,11 @@ Gfx *menuitemRender(Gfx *gdl, struct menurendercontext *context) case MENUITEMTYPE_CAROUSEL: return menuitemCarouselRender(gdl, context); case MENUITEMTYPE_MODEL: return menuitemModelRender(gdl, context); case MENUITEMTYPE_CONTROLLER: return menuitemControllerRender(gdl, context); + +#ifndef PLATFORM_N64 + case MENUITEMTYPE_COLORBOX: return menuitemColorBoxRender(gdl, context); +#endif + } return gdl; diff --git a/src/game/mplayer/mplayer.c b/src/game/mplayer/mplayer.c index 5dedcac62..4af5823a4 100644 --- a/src/game/mplayer/mplayer.c +++ b/src/game/mplayer/mplayer.c @@ -125,6 +125,7 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = { .crosshairsway = 1.f, \ .crouchmode = CROUCHMODE_TOGGLE_ANALOG, \ .extcontrols = true, \ + .crosshaircolour = 0x00ff0028, \ } struct extplayerconfig g_PlayerExtCfg[MAX_PLAYERS] = { @@ -2735,6 +2736,7 @@ struct mptrack g_MpTracks[] = { /*0x27*/ { MUSIC_SKEDARRUINS, 120, L_MISC_163, SOLOSTAGEINDEX_SKEDARRUINS }, // "Skedar Ruins" /*0x28*/ { MUSIC_SKEDARRUINS_X, 120, L_MISC_164, SOLOSTAGEINDEX_SKEDARRUINS }, // "Skedar Ruins X" /*0x29*/ { MUSIC_CREDITS, 120, L_MISC_165, SOLOSTAGEINDEX_SKEDARRUINS }, // "End Credits" + /*0x2a*/ { MUSIC_SKEDARRUINS_KING,120, L_MISC_261, SOLOSTAGEINDEX_SKEDARRUINS }, // "Skedar Warrior" (Skedar Leader) }; bool mpIsTrackUnlocked(s32 tracknum) diff --git a/src/game/sight.c b/src/game/sight.c index c7bfd5442..cea5377ba 100644 --- a/src/game/sight.c +++ b/src/game/sight.c @@ -23,6 +23,8 @@ #include #include "video.h" +#define SIGHT_COLOUR PLAYER_EXTCFG().crosshaircolour + static inline f32 sightGetScaleX(void) { return (videoGetAspect() / SCREEN_ASPECT); @@ -36,6 +38,7 @@ static inline s32 sightGetAdjustedX(const f32 x) #else +#define SIGHT_COLOUR 0x00ff0028 #define sightGetScaleX() 1.f #define sightGetAdjustedX(x) (x) @@ -459,7 +462,7 @@ Gfx *sightDrawAimer(Gfx *gdl, s32 x, s32 y, s32 radius, s32 cornergap, u32 colou s32 viewright = viewleft + viewwidth - 1; s32 viewbottom = viewtop + viewheight - 1; - gdl = textSetPrimColour(gdl, 0x00ff0028); + gdl = textSetPrimColour(gdl, SIGHT_COLOUR); #ifndef PLATFORM_N64 x = sightGetAdjustedX(x); @@ -619,7 +622,7 @@ Gfx *sightDrawDelayedAimer(Gfx *gdl, s32 x, s32 y, s32 radius, s32 cornergap, u3 boxx = xpos; boxy = ypos; - gdl = textSetPrimColour(gdl, 0x00ff0028); + gdl = textSetPrimColour(gdl, SIGHT_COLOUR); // Fill a 3x3 box at the live crosshair gDPHudRectangle(gdl++, x - 1, y - 1, x + 1, y - 1); @@ -677,7 +680,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton) // SIGHTTRACKTYPE_NONE is used for unarmed, but this appears to be // unreachable. The aimer is never drawn when unarmed. if (sighton) { - colour = 0x00ff0028; + colour = SIGHT_COLOUR; radius = 8; cornergap = 5; gdl = sightDrawAimer(gdl, x, y, radius, cornergap, colour); @@ -687,7 +690,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton) // For most guns, render the aimer if holding R if (sighton) { if (g_Vars.currentplayer->lookingatprop.prop == NULL) { - colour = 0x00ff0028; + colour = SIGHT_COLOUR; radius = 8; cornergap = 5; } else { @@ -716,7 +719,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton) s32 texty; if (g_Vars.currentplayer->lookingatprop.prop == NULL) { - colour = 0x00ff0028; + colour = SIGHT_COLOUR; radius = 8; cornergap = 5; } else { @@ -761,7 +764,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton) if (sighton) { if (g_Vars.currentplayer->lookingatprop.prop == NULL) { - colour = 0x00ff0028; + colour = SIGHT_COLOUR; radius = 8; cornergap = 5; } else { @@ -832,7 +835,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton) if (sighton) { if (g_Vars.currentplayer->lookingatprop.prop == NULL) { - colour = 0x00ff0028; + colour = SIGHT_COLOUR; radius = 8; cornergap = 5; } else { @@ -1252,7 +1255,7 @@ Gfx *sightDrawZoom(Gfx *gdl, bool sighton) if (showzoomrange) { gdl = text0f153628(gdl); - gdl = textSetPrimColour(gdl, 0x00ff0028); + gdl = textSetPrimColour(gdl, SIGHT_COLOUR); if (frac < 0.2f) { cornerwidth *= 0.2f; @@ -1436,7 +1439,7 @@ Gfx *sightDrawMaian(Gfx *gdl, bool sighton) gSPTri4(gdl++, 0, 4, 5, 5, 3, 6, 7, 6, 1, 4, 7, 2); gdl = func0f0d49c8(gdl); - gdl = textSetPrimColour(gdl, 0x00ff0028); + gdl = textSetPrimColour(gdl, SIGHT_COLOUR); // Draw border over inner points gDPHudRectangle(gdl++, x - 4, y - 4, x - 4, y + 4); // left @@ -1464,7 +1467,7 @@ Gfx *sightDrawTarget(Gfx *gdl) mainOverrideVariable("sout", &var80070f9c); mainOverrideVariable("sin", &var80070fa0); - gdl = textSetPrimColour(gdl, 0x00ff0028); + gdl = textSetPrimColour(gdl, SIGHT_COLOUR); #ifndef PLATFORM_N64 gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); diff --git a/src/include/constants.h b/src/include/constants.h index 2ebee8874..337af44d3 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -1694,6 +1694,10 @@ #define MENUITEMTYPE_CONTROLLER 0x19 #define MENUITEMTYPE_END 0x1a +#ifndef PLATFORM_N64 +#define MENUITEMTYPE_COLORBOX 0x1b +#endif + #define MENUMODELFLAG_HASSCALE 0x01 #define MENUMODELFLAG_HASPOSITION 0x02 #define MENUMODELFLAG_HASROTATION 0x04 diff --git a/src/include/game/menuitem.h b/src/include/game/menuitem.h index 27747bf71..79b868989 100644 --- a/src/include/game/menuitem.h +++ b/src/include/game/menuitem.h @@ -32,6 +32,10 @@ Gfx *menuitemLabelRender(Gfx *gdl, struct menurendercontext *context); Gfx *menuitemMeterRender(Gfx *gdl, struct menurendercontext *context); +#ifndef PLATFORM_N64 +Gfx *menuitemColorBoxRender(Gfx *gdl, struct menurendercontext *context); +#endif + Gfx *menuitemSelectableRender(Gfx *gdl, struct menurendercontext *context); bool menuitemSelectableTick(struct menuitem *item, struct menuinputs *inputs, u32 tickflags); diff --git a/src/include/types.h b/src/include/types.h index f8d24b7d7..5484bb145 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -6148,6 +6148,7 @@ struct extplayerconfig { f32 radialmenuspeed; f32 crosshairsway; s32 extcontrols; + u32 crosshaircolour; }; #endif