From ce73f2c1b1a1cbc9d425d7093653172eae0cc2fc Mon Sep 17 00:00:00 2001 From: Kai-Li Date: Fri, 7 Apr 2023 22:51:06 +0200 Subject: [PATCH] GENDER: Enable the user to select the gender - inspired by https://github.com/PadWorld-Entertainment/worldofpadman-fork/pull/41 - add "none" as a new gender which will force "they/them" to be used instead of e.g. "male" with "he/him" - add "model" as the new default gender which will force always to apply the gender of the selected player model (to keep old behavior) - also "none" is the fallback for a model if a gender is undefined in animations.cfg - add gender neutral event messages - fix minor typos in event messages - add gender selection option (model/male/female/neuter/none) in player settings menu; if "model" the gender is normally set by the player model via animations.cfg, else taken from user info "sex" - add a tool tip for gender selection option --- code/cgame/cg_event.c | 43 ++++++++------- code/cgame/cg_local.h | 3 +- code/cgame/cg_players.c | 56 +++++++++++-------- code/client/cl_main.c | 2 +- code/game/bg_public.h | 2 +- code/game/g_bot.c | 2 +- code/game/g_client.c | 46 ++++++++++------ code/ui/ui_playersettings.c | 104 +++++++++++++++++++++++------------- 8 files changed, 156 insertions(+), 102 deletions(-) diff --git a/code/cgame/cg_event.c b/code/cgame/cg_event.c index e0f91987d..156e73584 100644 --- a/code/cgame/cg_event.c +++ b/code/cgame/cg_event.c @@ -156,40 +156,39 @@ static void CG_Obituary(entityState_t *ent) { gender = ci->gender; switch (mod) { case MOD_BALLOONY_SPLASH: - if (gender == GENDER_FEMALE) + if (gender == GENDER_MALE) + message = "tripped on his own water bomb"; + else if (gender == GENDER_FEMALE) message = "tripped on her own water bomb"; else if (gender == GENDER_NEUTER) message = "tripped on its own water bomb"; else - message = "tripped on his own water bomb"; + message = "tripped on their own water bomb"; break; case MOD_BETTY_SPLASH: - if (gender == GENDER_FEMALE) + if (gender == GENDER_MALE) + message = "blew himself up"; + else if (gender == GENDER_FEMALE) message = "blew herself up"; else if (gender == GENDER_NEUTER) message = "blew itself up"; else - message = "blew himself up"; + message = "blew themselves up"; break; case MOD_BUBBLEG_SPLASH: - if (gender == GENDER_FEMALE) + if (gender == GENDER_MALE) + message = "melted himself"; + else if (gender == GENDER_FEMALE) message = "melted herself"; else if (gender == GENDER_NEUTER) message = "melted itself"; else - message = "melted himself"; + message = "melted themselves"; break; case MOD_IMPERIUS_SPLASH: message = "should have used a smaller gun"; break; - default: /* - if ( gender == GENDER_FEMALE ) - message = "killed herself"; - else if ( gender == GENDER_NEUTER ) - message = "killed itself"; - else - message = "killed himself"; - break;*/ + default: message = "did the lemming thing"; break; } @@ -206,19 +205,19 @@ static void CG_Obituary(entityState_t *ent) { if (cgs.gametype < GT_TEAM) { if (cgs.gametype == GT_LPS) { - const char *gender_strings[] = {"he", "she", "it", 0}; + const char *gender_strings[] = {"they have", "he has", "she has", "it has", NULL}; CASSERT(ARRAY_LEN(gender_strings) == GENDER_MAX + 1); gender = ci->gender; - if (gender > 2 || gender < 0) - gender = 2; + if (gender >= GENDER_MAX || gender < GENDER_NONE) + gender = GENDER_NONE; if (ent->generic1 == 0) - s = va("You fragged %s\n%s has no lives left.", targetName, gender_strings[gender]); + s = va("You fragged %s,\n%s no lives left.", targetName, gender_strings[gender]); else if (ent->generic1 == 1) - s = va("You fragged %s\n%s has 1 live left.", targetName, gender_strings[gender]); + s = va("You fragged %s,\n%s 1 life left.", targetName, gender_strings[gender]); else - s = va("You fragged %s\n%s has %i lives left.", targetName, gender_strings[gender], ent->generic1); + s = va("You fragged %s,\n%s %i lives left.", targetName, gender_strings[gender], ent->generic1); } else s = va("You fragged %s\n%s place with %i", targetName, CG_PlaceString(cg.snap->ps.persistant[PERS_RANK] + 1), cg.snap->ps.persistant[PERS_SCORE]); @@ -282,7 +281,7 @@ static void CG_Obituary(entityState_t *ent) { break; case MOD_SPLASHER: message = "was splashed by"; - message2 = "'s splasher"; + message2 = "'s Splasher"; break; case MOD_BOASTER: message = "was showered by"; @@ -294,7 +293,7 @@ static void CG_Obituary(entityState_t *ent) { break; case MOD_KILLERDUCKS: message = "was hunted & bitten to death by"; - message2 = "'s KillerDuck"; + message2 = "'s Killerduck"; break; case MOD_TELEFRAG: message = "tried to invade"; diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 5ed607213..12ff13cd7 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -369,7 +369,8 @@ typedef struct { float headScale; footstep_t footsteps; - gender_t gender; // from model + gender_t gender; // user settings (can also be from model) + gender_t genderModel; // cached value from model (animation.cfg) qhandle_t legsModel; qhandle_t legsSkin; diff --git a/code/cgame/cg_players.c b/code/cgame/cg_players.c index 2ceec2a3b..d584aec2e 100644 --- a/code/cgame/cg_players.c +++ b/code/cgame/cg_players.c @@ -108,7 +108,6 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t *ci) { ci->footsteps = FOOTSTEP_NORMAL; VectorClear(ci->headOffset); ci->headScale = 1.0f; - ci->gender = GENDER_MALE; ci->fixedlegs = qfalse; ci->fixedtorso = qfalse; @@ -167,14 +166,15 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t *ci) { } else if (!Q_stricmp(token, "sex")) { token = COM_Parse(&text_p); if (!token[0]) { + ci->genderModel = GENDER_NONE; break; } - if (token[0] == 'f' || token[0] == 'F') { - ci->gender = GENDER_FEMALE; + if (token[0] == 'm' || token[0] == 'M') { + ci->genderModel = GENDER_MALE; + } else if (token[0] == 'f' || token[0] == 'F') { + ci->genderModel = GENDER_FEMALE; } else if (token[0] == 'n' || token[0] == 'N') { - ci->gender = GENDER_NEUTER; - } else { - ci->gender = GENDER_MALE; + ci->genderModel = GENDER_NEUTER; } continue; } else if (!Q_stricmp(token, "fixedlegs")) { @@ -195,7 +195,6 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t *ci) { // read information for each frame for (i = 0; i < MAX_ANIMATIONS; i++) { - token = COM_Parse(&text_p); if (!token[0]) { if (i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE) { @@ -261,8 +260,8 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t *ci) { if (fps == 0) { fps = 1; } - animations[i].frameLerp = 1000 / fps; - animations[i].initialLerp = 1000 / fps; + animations[i].frameLerp = 1000.0f / fps; + animations[i].initialLerp = 1000.0f / fps; } if (i != MAX_ANIMATIONS) { @@ -668,18 +667,21 @@ static void CG_LoadClientInfo(int clientNum, clientInfo_t *ci) { CG_ResetPlayerEntity(&cg_entities[i]); } } + + if (ci->gender == GENDER_MAX) { + ci->gender = ci->genderModel; + } } -/* -====================== -CG_CopyClientInfoModel -====================== -*/ -static void CG_CopyClientInfoModel(clientInfo_t *from, clientInfo_t *to) { +/** + * @brief Copies the attributes of a model from its @c animation.cfg properties to the new @c clientInfo_t + * @sa CG_ParseAnimationFile() + */ +static void CG_CopyClientInfoModel(const clientInfo_t *from, clientInfo_t *to) { VectorCopy(from->headOffset, to->headOffset); to->headScale = from->headScale; to->footsteps = from->footsteps; - to->gender = from->gender; + to->genderModel = from->genderModel; to->legsModel = from->legsModel; to->legsSkin = from->legsSkin; @@ -700,7 +702,7 @@ CG_ScanForExistingClientInfo */ static qboolean CG_ScanForExistingClientInfo(clientInfo_t *ci) { int i; - clientInfo_t *match; + const clientInfo_t *match; for (i = 0; i < cgs.maxclients; i++) { match = &cgs.clientinfo[i]; @@ -801,11 +803,9 @@ static void CG_SetDeferredClientInfo(int clientNum, clientInfo_t *ci) { CG_LoadClientInfo(clientNum, ci); } -/* -====================== -CG_NewClientInfo -====================== -*/ +/** + * @sa ClientUserinfoChanged() + */ void CG_NewClientInfo(int clientNum) { clientInfo_t *ci; clientInfo_t newInfo; @@ -879,6 +879,17 @@ void CG_NewClientInfo(int clientNum) { // team leader v = Info_ValueForKey(configstring, "tl"); newInfo.teamLeader = atoi(v); + + // sex + // if a sex option is set in the userinfo string we take this, + // otherwise we check for GENDER_MAX in CG_ParseAnimationFile() to use the + // setting from animation.cfg + newInfo.gender = GENDER_MAX; + v = Info_ValueForKey(configstring, "s"); + if (v[0] != '\0') { + newInfo.gender = atoi(v); + } + oldTeam = ci->team; // this may be run before the first snapshot arrives @@ -987,6 +998,7 @@ void CG_NewClientInfo(int clientNum) { // replace whatever was there with the new one newInfo.infoValid = qtrue; + *ci = newInfo; // if the local client changed teams in a team gametype, adjust team- and enemymodels diff --git a/code/client/cl_main.c b/code/client/cl_main.c index dcbd65683..5e3653847 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -3394,7 +3394,7 @@ void CL_Init(void) { Cvar_Get("team_model", "padman", CVAR_USERINFO | CVAR_ARCHIVE); Cvar_Get("team_headmodel", "padman", CVAR_USERINFO | CVAR_ARCHIVE); Cvar_Get("handicap", "100", CVAR_USERINFO | CVAR_ARCHIVE); - Cvar_Get("sex", "male", CVAR_USERINFO | CVAR_ARCHIVE); + Cvar_Get("sex", "model", CVAR_USERINFO | CVAR_ARCHIVE); Cvar_Get("cl_anonymous", "0", CVAR_USERINFO | CVAR_ARCHIVE); Cvar_Get("password", "", CVAR_USERINFO); diff --git a/code/game/bg_public.h b/code/game/bg_public.h index fb81a9483..3e3d8a4e2 100644 --- a/code/game/bg_public.h +++ b/code/game/bg_public.h @@ -160,7 +160,7 @@ typedef enum { int convertGTStringToGTNumber(const char *argStr); -typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER, GENDER_MAX } gender_t; +typedef enum { GENDER_NONE, GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER, GENDER_MAX } gender_t; /* =================================================================================== diff --git a/code/game/g_bot.c b/code/game/g_bot.c index 62e257801..1088d05c3 100644 --- a/code/game/g_bot.c +++ b/code/game/g_bot.c @@ -576,7 +576,7 @@ static void G_AddBot(const char *name, float skill, const char *team, int delay, // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if (clientNum == -1) { - G_Printf(S_COLOR_RED "Unable to add bot. All player slots are in use.\n"); + G_Printf(S_COLOR_RED "Unable to add bot. All player slots are in use.\n"); G_Printf(S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n"); return; } diff --git a/code/game/g_client.c b/code/game/g_client.c index 207dc22cc..859960df8 100644 --- a/code/game/g_client.c +++ b/code/game/g_client.c @@ -741,17 +741,15 @@ static void ClientCleanName(const char *in, char *out, int outSize) { Q_strncpyz(out, "UnnamedPlayer", outSize); } -/* -=========== -ClientUserInfoChanged - -Called from ClientConnect when the player first connects and -directly by the server system when the player updates a userinfo variable. - -The game can override any of the settings and call trap_SetUserinfo -if desired. -============ -*/ +/** + * Called from ClientConnect when the player first connects and + * directly by the server system when the player updates a userinfo variable. + * + * The game can override any of the settings and call trap_SetUserinfo + * if desired. + * + * @see CG_NewClientInfo() + */ void ClientUserinfoChanged(int clientNum) { gentity_t *ent; int teamLeader, team, health; @@ -763,6 +761,7 @@ void ClientUserinfoChanged(int clientNum) { char c1[MAX_INFO_STRING]; char c2[MAX_INFO_STRING]; char userinfo[MAX_INFO_STRING]; + gender_t gender; ent = g_entities + clientNum; client = ent->client; @@ -815,6 +814,20 @@ void ClientUserinfoChanged(int clientNum) { } client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; + // set gender + s = Info_ValueForKey(userinfo, "sex"); + if (!Q_stricmp(s, "neuter")) { + gender = GENDER_NEUTER; + } else if (!Q_stricmp(s, "female")) { + gender = GENDER_FEMALE; + } else if (!Q_stricmp(s, "male")) { + gender = GENDER_MALE; + } else if (!Q_stricmp(s, "none")) { + gender = GENDER_NONE; + } else { + gender = GENDER_MAX; + } + // set model if (g_gametype.integer >= GT_TEAM) { Q_strncpyz(model, Info_ValueForKey(userinfo, "team_model"), sizeof(model)); @@ -849,16 +862,15 @@ void ClientUserinfoChanged(int clientNum) { int rnd; rnd = random() * 5.9; rnd_str = va("%d", rnd); - s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tl\\%" - "d\\sl\\%s", + s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tl\\%d" + "\\sl\\%s", client->pers.netname, team, model, headModel, c1, rnd_str, client->pers.maxHealth, client->sess.wins, - client->sess.losses, Info_ValueForKey(userinfo, "skill"), teamLeader, - client->sess.selectedlogo); + client->sess.losses, Info_ValueForKey(userinfo, "skill"), teamLeader, client->sess.selectedlogo); // cyr} } else { - s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tl\\%d\\sl\\%s", + s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tl\\%d\\sl\\%s\\s\\%i", client->pers.netname, client->sess.sessionTeam, model, headModel, c1, c2, client->pers.maxHealth, - client->sess.wins, client->sess.losses, teamLeader, client->sess.selectedlogo); + client->sess.wins, client->sess.losses, teamLeader, client->sess.selectedlogo, (int)gender); } trap_SetConfigstring(CS_PLAYERS + clientNum, s); diff --git a/code/ui/ui_playersettings.c b/code/ui/ui_playersettings.c index 73907b06b..97d1f42ad 100644 --- a/code/ui/ui_playersettings.c +++ b/code/ui/ui_playersettings.c @@ -39,20 +39,21 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define ID_NAME 10 #define ID_HANDICAP 11 -#define ID_SKINCOLOR 12 -#define ID_EFFECTS 13 -#define ID_BACK 14 - -#define ID_PREVMODEL 15 -#define ID_NEXTMODEL 16 -#define ID_PREVSKIN 17 -#define ID_NEXTSKIN 18 -#define ID_MICON 19 //+4 -#define ID_SICON 24//+2 -#define ID_PLAYERMODEL 27 -#define ID_SPRAYCOLOR 28 -#define ID_NEXTLOGO 29 -#define ID_PREVLOGO 30 +#define ID_GENDER 12 +#define ID_SKINCOLOR 13 +#define ID_EFFECTS 14 +#define ID_BACK 15 + +#define ID_PREVMODEL 16 +#define ID_NEXTMODEL 17 +#define ID_PREVSKIN 18 +#define ID_NEXTSKIN 19 +#define ID_MICON 20 //+4 +#define ID_SICON 25//+2 +#define ID_PLAYERMODEL 28 +#define ID_SPRAYCOLOR 29 +#define ID_NEXTLOGO 30 +#define ID_PREVLOGO 31 #define MAX_NAMELENGTH 20 @@ -73,9 +74,8 @@ typedef struct { menutext_s nameheader; menufield_s name; - menutext_s handicapheader; menulist_s handicap; - menutext_s skincolorheader; + menulist_s gender; menulist_s skincolor; menutext_s logoheader; menulist_s effects; @@ -116,6 +116,8 @@ static playersettings_t s_playersettings; static int gamecodetoui[] = {4, 2, 3, 0, 5, 1, 6}; static int uitogamecode[] = {4, 6, 2, 3, 1, 5, 7}; +static const char *gender_items[] = {"Model", "Male", "Female", "Neuter", "None", NULL}; + static const char *handicap_items[] = {S_COLOR_WHITE "None", S_COLOR_WHITE "90", S_COLOR_WHITE "80", @@ -251,6 +253,7 @@ PlayerSettings_SaveChanges ================= */ static void PlayerSettings_SaveChanges(void) { +int g; // name trap_Cvar_Set("name", s_playersettings.name.field.buffer); @@ -261,6 +264,21 @@ static void PlayerSettings_SaveChanges(void) { // effects color trap_Cvar_SetValue("color1", uitogamecode[s_playersettings.effects.curvalue]); + // gender + g = s_playersettings.gender.curvalue; + if (g > 3) { + trap_Cvar_Set("sex", "none"); + } else if (g == 1) { + trap_Cvar_Set("sex", "male"); + } else if (g == 2) { + trap_Cvar_Set("sex", "female"); + } else if (g == 3) { + trap_Cvar_Set("sex", "neuter"); + } else { + trap_Cvar_Set("sex", "model"); + } + + // spray logo trap_Cvar_Set("syc_logo", uis.spraylogoNames[s_playersettings.slogo_num]); if (trap_Cvar_VariableValue("cl_paused")) { @@ -312,6 +330,7 @@ static void PlayerSettings_SetMenuItems(void) { vec3_t viewangles; int c; int h; + char gStr[32]; // name Q_strncpyz(s_playersettings.name.field.buffer, UI_Cvar_VariableString("name"), @@ -377,6 +396,19 @@ static void PlayerSettings_SetMenuItems(void) { h = Com_Clamp(10, 100, trap_Cvar_VariableValue("handicap")); s_playersettings.handicap.curvalue = 10 - h / 10; + // gender + trap_Cvar_VariableStringBuffer("sex", gStr, sizeof(gStr)); + if (!Q_stricmp(gStr, "none")) { + s_playersettings.gender.curvalue = 4; + } else if (!Q_stricmp(gStr, "neuter")) { + s_playersettings.gender.curvalue = 3; + } else if (!Q_stricmp(gStr, "female")) { + s_playersettings.gender.curvalue = 2; + } else if (!Q_stricmp(gStr, "male")) { + s_playersettings.gender.curvalue = 1; + } else { + s_playersettings.gender.curvalue = 0; + } } static int GetSpecialSkinScore(const char *iconPath) { @@ -726,6 +758,7 @@ static void PlayerSettings_MenuEvent(void *ptr, int event) { switch (tmpid) { case ID_HANDICAP: + case ID_GENDER: break; case ID_SKINCOLOR: @@ -1033,42 +1066,40 @@ static void PlayerSettings_MenuInit(void) { s_playersettings.name.generic.bottom = y + 2 * (BIGCHAR_HEIGHT); y += 2 * (BIGCHAR_HEIGHT + 2); - s_playersettings.handicapheader.generic.type = MTYPE_TEXT; - s_playersettings.handicapheader.generic.x = XPOSITION; - s_playersettings.handicapheader.generic.y = y; - s_playersettings.handicapheader.string = "Handicap:"; - s_playersettings.handicapheader.style = UI_LEFT | UI_SMALLFONT; - s_playersettings.handicapheader.color = color_yellow; - - y += BIGCHAR_HEIGHT + 2; s_playersettings.handicap.generic.type = MTYPE_SPINCONTROL; - s_playersettings.handicap.generic.name = ""; + s_playersettings.handicap.generic.name = "Cap:"; s_playersettings.handicap.generic.flags = QMF_SMALLFONT; s_playersettings.handicap.generic.id = ID_HANDICAP; s_playersettings.handicap.generic.callback = PlayerSettings_MenuEvent; - s_playersettings.handicap.generic.x = XPOSITION; + s_playersettings.handicap.generic.x = XPOSITION + 48; s_playersettings.handicap.generic.y = y; s_playersettings.handicap.itemnames = handicap_items; y += BIGCHAR_HEIGHT + 2; - s_playersettings.skincolorheader.generic.type = MTYPE_TEXT; - s_playersettings.skincolorheader.generic.x = XPOSITION; - s_playersettings.skincolorheader.generic.y = y; - s_playersettings.skincolorheader.string = "Skin Color:"; - s_playersettings.skincolorheader.style = UI_LEFT | UI_SMALLFONT; - s_playersettings.skincolorheader.color = color_yellow; + s_playersettings.gender.generic.type = MTYPE_SPINCONTROL; + s_playersettings.gender.generic.name = "Sex:"; + s_playersettings.gender.generic.flags = QMF_SMALLFONT; + s_playersettings.gender.generic.id = ID_GENDER; + s_playersettings.gender.generic.callback = PlayerSettings_MenuEvent; + s_playersettings.gender.generic.x = XPOSITION + 48; + s_playersettings.gender.generic.y = y; + s_playersettings.gender.itemnames = gender_items; + s_playersettings.gender.generic.toolTip = + "Choose a desired gender, which is normally determined by the chosen player model, or choose " + "none to deactivate the gender. Default is model. Note: none forces the game to use they/them " + "instead of he/his, she/her, or it/its for your character."; y += BIGCHAR_HEIGHT + 2; s_playersettings.skincolor.generic.type = MTYPE_SPINCONTROL; - s_playersettings.skincolor.generic.name = ""; + s_playersettings.skincolor.generic.name = "Color:"; s_playersettings.skincolor.generic.flags = QMF_SMALLFONT; s_playersettings.skincolor.generic.id = ID_SKINCOLOR; s_playersettings.skincolor.generic.callback = PlayerSettings_MenuEvent; - s_playersettings.skincolor.generic.x = XPOSITION; + s_playersettings.skincolor.generic.x = XPOSITION + 48; s_playersettings.skincolor.generic.y = y; s_playersettings.skincolor.itemnames = skincolor_items; - y += BIGCHAR_HEIGHT + 2; + y += 2 * (BIGCHAR_HEIGHT + 2); s_playersettings.logoheader.generic.type = MTYPE_TEXT; s_playersettings.logoheader.generic.x = XPOSITION; s_playersettings.logoheader.generic.y = y; @@ -1098,9 +1129,8 @@ static void PlayerSettings_MenuInit(void) { Menu_AddItem(&s_playersettings.menu, &s_playersettings.nameheader); Menu_AddItem(&s_playersettings.menu, &s_playersettings.name); - Menu_AddItem(&s_playersettings.menu, &s_playersettings.handicapheader); Menu_AddItem(&s_playersettings.menu, &s_playersettings.handicap); - Menu_AddItem(&s_playersettings.menu, &s_playersettings.skincolorheader); + Menu_AddItem(&s_playersettings.menu, &s_playersettings.gender); Menu_AddItem(&s_playersettings.menu, &s_playersettings.skincolor); Menu_AddItem(&s_playersettings.menu, &s_playersettings.logoheader); Menu_AddItem(&s_playersettings.menu, &s_playersettings.logoleft);