Squashed commit of the following:

commit 767e3a64f0d5fd27ef56de6e93221e9b2016a0c7
Author: Marrub <marrub.xz@gmail.com>
Date:   Tue Oct 30 04:01:09 2018 -0400

    ProMessage -> PronounMessage

commit 305477f63fb669f8cf2d9f6d609ed3988f437664
Author: Marrub <marrub.xz@gmail.com>
Date:   Mon Oct 29 23:56:58 2018 -0400

    improve variable naming

commit f3f0245d0cdcc1b0a8a9b74806bc8954be747f40
Author: Marrub <marrub.xz@gmail.com>
Date:   Mon Oct 29 19:52:32 2018 -0400

    add "neutral" gender option and better obit formatting
This commit is contained in:
Marrub 2018-10-30 16:41:04 -04:00 committed by Christoph Oelckers
parent 94688a3700
commit 0b460ccb03
11 changed files with 91 additions and 60 deletions

View file

@ -59,7 +59,7 @@ struct SoundAndString
// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void SexMessage (const char *from, char *to, int gender, void PronounMessage (const char *from, char *to, int pronoun,
const char *victim, const char *killer); const char *victim, const char *killer);
// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -266,7 +266,7 @@ bool AnnounceKill (AActor *killer, AActor *killee)
{ {
char assembled[1024]; char assembled[1024];
SexMessage (message, assembled, killee->player->userinfo.GetGender(), PronounMessage (message, assembled, killee->player->userinfo.GetGender(),
killee->player->userinfo.GetName(), killerName); killee->player->userinfo.GetName(), killerName);
Printf (PRINT_MEDIUM, "%s\n", assembled); Printf (PRINT_MEDIUM, "%s\n", assembled);
} }
@ -298,7 +298,7 @@ bool AnnounceTelefrag (AActor *killer, AActor *killee)
{ {
char assembled[1024]; char assembled[1024];
SexMessage (message, assembled, killee->player->userinfo.GetGender(), PronounMessage (message, assembled, killee->player->userinfo.GetGender(),
killee->player->userinfo.GetName(), killer->player->userinfo.GetName()); killee->player->userinfo.GetName(), killer->player->userinfo.GetName());
Printf (PRINT_MEDIUM, "%s\n", assembled); Printf (PRINT_MEDIUM, "%s\n", assembled);
} }

View file

@ -36,8 +36,17 @@
#include "c_cvars.h" #include "c_cvars.h"
enum
{
GENDER_MALE,
GENDER_FEMALE,
GENDER_NEUTER,
GENDER_OBJECT,
GENDER_MAX
};
int D_GenderToInt (const char *gender); int D_GenderToInt (const char *gender);
extern const char *GenderNames[3]; extern const char *GenderNames[GENDER_MAX];
int D_PlayerClassToInt (const char *classname); int D_PlayerClassToInt (const char *classname);

View file

@ -83,7 +83,7 @@ enum
INFO_ClassicFlight, INFO_ClassicFlight,
}; };
const char *GenderNames[3] = { "male", "female", "other" }; const char *GenderNames[GENDER_MAX] = { "male", "female", "neutral", "other" };
// Replace \ with %/ and % with %% // Replace \ with %/ and % with %%
FString D_EscapeUserInfo (const char *str) FString D_EscapeUserInfo (const char *str)
@ -136,12 +136,14 @@ FString D_UnescapeUserInfo (const char *str, size_t len)
int D_GenderToInt (const char *gender) int D_GenderToInt (const char *gender)
{ {
if (!stricmp (gender, "female")) if (gender[0] == 'f')
return GENDER_FEMALE; return GENDER_FEMALE;
else if (!stricmp (gender, "other") || !stricmp (gender, "cyborg")) else if (gender[0] == 'm')
return GENDER_MALE;
else if (gender[0] == 'n')
return GENDER_NEUTER; return GENDER_NEUTER;
else else
return GENDER_MALE; return GENDER_OBJECT;
} }
int D_PlayerClassToInt (const char *classname) int D_PlayerClassToInt (const char *classname)
@ -726,7 +728,8 @@ void D_WriteUserInfoStrings (int pnum, uint8_t **stream, bool compact)
case NAME_Gender: case NAME_Gender:
*stream += sprintf(*((char **)stream), "\\%s", *stream += sprintf(*((char **)stream), "\\%s",
*static_cast<FIntCVar *>(pair->Value) == GENDER_FEMALE ? "female" : *static_cast<FIntCVar *>(pair->Value) == GENDER_FEMALE ? "female" :
*static_cast<FIntCVar *>(pair->Value) == GENDER_NEUTER ? "other" : "male"); *static_cast<FIntCVar *>(pair->Value) == GENDER_MALE ? "male" :
*static_cast<FIntCVar *>(pair->Value) == GENDER_NEUTER ? "neutral" : "other");
break; break;
case NAME_PlayerClass: case NAME_PlayerClass:

View file

@ -34,6 +34,8 @@
#include "a_weapons.h" #include "a_weapons.h"
#include "d_netinf.h"
// The player data structure depends on a number // The player data structure depends on a number
// of other structs: items (internal inventory), // of other structs: items (internal inventory),
// animation states (closely tied to the sprites // animation states (closely tied to the sprites
@ -261,13 +263,6 @@ public:
extern TArray<FPlayerClass> PlayerClasses; extern TArray<FPlayerClass> PlayerClasses;
// User info (per-player copies of each CVAR_USERINFO cvar) // User info (per-player copies of each CVAR_USERINFO cvar)
enum
{
GENDER_MALE,
GENDER_FEMALE,
GENDER_NEUTER
};
struct userinfo_t : TMap<FName,FBaseCVar *> struct userinfo_t : TMap<FName,FBaseCVar *>
{ {
~userinfo_t(); ~userinfo_t();

View file

@ -207,7 +207,13 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged)
// only allow if the menu is active to prevent abuse. // only allow if the menu is active to prevent abuse.
if (self == CurrentMenu) if (self == CurrentMenu)
{ {
cvar_set("gender", v == 0 ? "male" : v == 1 ? "female" : "other"); switch(v)
{
case 0: cvar_set("gender", "male"); break;
case 1: cvar_set("gender", "female"); break;
case 2: cvar_set("gender", "neutral"); break;
case 3: cvar_set("gender", "other"); break;
}
} }
return 0; return 0;
} }

View file

@ -112,30 +112,34 @@ void P_TouchSpecialThing (AActor *special, AActor *toucher)
// [RH] // [RH]
// SexMessage: Replace parts of strings with gender-specific pronouns // PronounMessage: Replace parts of strings with player-specific pronouns
// //
// The following expansions are performed: // The following expansions are performed:
// %g -> he/she/it // %g -> he/she/they/it
// %h -> him/her/it // %h -> him/her/them/it
// %p -> his/her/its // %p -> his/her/their/its
// %s -> his/hers/theirs/its
// %r -> he's/she's/they're/it's
// %o -> other (victim) // %o -> other (victim)
// %k -> killer // %k -> killer
// //
void SexMessage (const char *from, char *to, int gender, const char *victim, const char *killer) void PronounMessage (const char *from, char *to, int pronoun, const char *victim, const char *killer)
{ {
static const char *genderstuff[3][3] = static const char *pronouns[GENDER_MAX][5] =
{ {
{ "he", "him", "his" }, { "he", "him", "his", "his", "he's" },
{ "she", "her", "her" }, { "she", "her", "her", "hers", "she's" },
{ "it", "it", "its" } { "they", "them", "their", "theirs", "they're" },
{ "it", "it", "its", "its'", "it's" }
}; };
static const int gendershift[3][3] = static const int pronounshift[GENDER_MAX][5] =
{ {
{ 2, 3, 3 }, { 2, 3, 3, 3, 4 },
{ 3, 3, 3 }, { 3, 3, 3, 4, 5 },
{ 2, 2, 3 } { 4, 4, 5, 6, 7 },
{ 2, 2, 3, 4, 4 }
}; };
const char *subst = NULL; const char *substitute = NULL;
do do
{ {
@ -145,32 +149,34 @@ void SexMessage (const char *from, char *to, int gender, const char *victim, con
} }
else else
{ {
int gendermsg = -1; int grammarcase = -1;
switch (from[1]) switch (from[1])
{ {
case 'g': gendermsg = 0; break; case 'g': grammarcase = 0; break; // Subject
case 'h': gendermsg = 1; break; case 'h': grammarcase = 1; break; // Object
case 'p': gendermsg = 2; break; case 'p': grammarcase = 2; break; // Possessive Determiner
case 'o': subst = victim; break; case 's': grammarcase = 3; break; // Possessive Pronoun
case 'k': subst = killer; break; case 'r': grammarcase = 4; break; // Perfective
case 'o': substitute = victim; break;
case 'k': substitute = killer; break;
} }
if (subst != NULL) if (substitute != nullptr)
{ {
size_t len = strlen (subst); size_t len = strlen (substitute);
memcpy (to, subst, len); memcpy (to, substitute, len);
to += len; to += len;
from++; from++;
subst = NULL; substitute = nullptr;
} }
else if (gendermsg < 0) else if (grammarcase < 0)
{ {
*to++ = '%'; *to++ = '%';
} }
else else
{ {
strcpy (to, genderstuff[gender][gendermsg]); strcpy (to, pronouns[pronoun][grammarcase]);
to += gendershift[gender][gendermsg]; to += pronounshift[pronoun][grammarcase];
from++; from++;
} }
} }
@ -268,7 +274,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
if (message == NULL || strlen(message) <= 0) if (message == NULL || strlen(message) <= 0)
return; return;
SexMessage (message, gendermessage, self->player->userinfo.GetGender(), PronounMessage (message, gendermessage, self->player->userinfo.GetGender(),
self->player->userinfo.GetName(), attacker->player->userinfo.GetName()); self->player->userinfo.GetName(), attacker->player->userinfo.GetName());
Printf (PRINT_MEDIUM, "%s\n", gendermessage); Printf (PRINT_MEDIUM, "%s\n", gendermessage);
} }
@ -402,7 +408,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
player->fragcount--; player->fragcount--;
if (deathmatch && player->spreecount >= 5 && cl_showsprees) if (deathmatch && player->spreecount >= 5 && cl_showsprees)
{ {
SexMessage (GStrings("SPREEKILLSELF"), buff, PronounMessage (GStrings("SPREEKILLSELF"), buff,
player->userinfo.GetGender(), player->userinfo.GetName(), player->userinfo.GetGender(), player->userinfo.GetName(),
player->userinfo.GetName()); player->userinfo.GetName());
StatusBar->AttachMessage (Create<DHUDMessageFadeOut>(SmallFont, buff, StatusBar->AttachMessage (Create<DHUDMessageFadeOut>(SmallFont, buff,
@ -460,7 +466,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
{ {
if (!AnnounceSpreeLoss (this)) if (!AnnounceSpreeLoss (this))
{ {
SexMessage (GStrings("SPREEOVER"), buff, player->userinfo.GetGender(), PronounMessage (GStrings("SPREEOVER"), buff, player->userinfo.GetGender(),
player->userinfo.GetName(), source->player->userinfo.GetName()); player->userinfo.GetName(), source->player->userinfo.GetName());
StatusBar->AttachMessage (Create<DHUDMessageFadeOut> (SmallFont, buff, StatusBar->AttachMessage (Create<DHUDMessageFadeOut> (SmallFont, buff,
1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R'));
@ -470,7 +476,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
{ {
if (!AnnounceSpree (source)) if (!AnnounceSpree (source))
{ {
SexMessage (spreemsg, buff, player->userinfo.GetGender(), PronounMessage (spreemsg, buff, player->userinfo.GetGender(),
player->userinfo.GetName(), source->player->userinfo.GetName()); player->userinfo.GetName(), source->player->userinfo.GetName());
StatusBar->AttachMessage (Create<DHUDMessageFadeOut> (SmallFont, buff, StatusBar->AttachMessage (Create<DHUDMessageFadeOut> (SmallFont, buff,
1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R')); 1.5f, 0.2f, 0, 0, CR_WHITE, 3.f, 0.5f), MAKE_ID('K','S','P','R'));
@ -520,7 +526,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
if (!AnnounceMultikill (source)) if (!AnnounceMultikill (source))
{ {
SexMessage (multimsg, buff, player->userinfo.GetGender(), PronounMessage (multimsg, buff, player->userinfo.GetGender(),
player->userinfo.GetName(), source->player->userinfo.GetName()); player->userinfo.GetName(), source->player->userinfo.GetName());
StatusBar->AttachMessage (Create<DHUDMessageFadeOut> (SmallFont, buff, StatusBar->AttachMessage (Create<DHUDMessageFadeOut> (SmallFont, buff,
1.5f, 0.8f, 0, 0, CR_RED, 3.f, 0.5f), MAKE_ID('M','K','I','L')); 1.5f, 0.8f, 0, 0, CR_RED, 3.f, 0.5f), MAKE_ID('M','K','I','L'));

View file

@ -80,7 +80,7 @@ struct FRandomSoundList
struct FPlayerClassLookup struct FPlayerClassLookup
{ {
FString Name; FString Name;
uint16_t ListIndex[3]; // indices into PlayerSounds (0xffff means empty) uint16_t ListIndex[GENDER_MAX]; // indices into PlayerSounds (0xffff means empty)
}; };
// Used to lookup a sound like "*grunt". This contains all player sounds for // Used to lookup a sound like "*grunt". This contains all player sounds for
@ -1622,7 +1622,8 @@ static int S_AddPlayerClass (const char *name)
FPlayerClassLookup lookup; FPlayerClassLookup lookup;
lookup.Name = name; lookup.Name = name;
lookup.ListIndex[2] = lookup.ListIndex[1] = lookup.ListIndex[0] = 0xffff; for(int i = 0; i < GENDER_MAX; i++)
lookup.ListIndex[i] = 0xffff;
cnum = (int)PlayerClassLookups.Push (lookup); cnum = (int)PlayerClassLookups.Push (lookup);
PlayerClassesIsSorted = false; PlayerClassesIsSorted = false;
@ -1770,11 +1771,11 @@ static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid)
{ {
int g; int g;
for (g = 0; g < 3 && listidx == 0xffff; ++g) for (g = 0; g < GENDER_MAX && listidx == 0xffff; ++g)
{ {
listidx = PlayerClassLookups[classidx].ListIndex[g]; listidx = PlayerClassLookups[classidx].ListIndex[g];
} }
if (g == 3) if (g == GENDER_MAX)
{ // No sounds defined at all for this class (can this happen?) { // No sounds defined at all for this class (can this happen?)
if (classidx != DefPlayerClass) if (classidx != DefPlayerClass)
{ {
@ -1796,7 +1797,7 @@ static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid)
{ // This sound is unavailable. { // This sound is unavailable.
if (ingender != 0) if (ingender != 0)
{ // Try "male" { // Try "male"
return S_LookupPlayerSound (classidx, 0, refid); return S_LookupPlayerSound (classidx, GENDER_MALE, refid);
} }
if (classidx != DefPlayerClass) if (classidx != DefPlayerClass)
{ // Try the default class. { // Try the default class.
@ -1912,7 +1913,7 @@ bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2)
int S_FindSkinnedSound (AActor *actor, FSoundID refid) int S_FindSkinnedSound (AActor *actor, FSoundID refid)
{ {
const char *pclass; const char *pclass;
int gender = GENDER_MALE; int gender = 0;
if (actor != NULL && actor->IsKindOf(RUNTIME_CLASS(APlayerPawn))) if (actor != NULL && actor->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{ {
@ -2074,7 +2075,7 @@ void S_MarkPlayerSounds (const char *playerclass)
{ {
classidx = DefPlayerClass; classidx = DefPlayerClass;
} }
for (int g = 0; g < 3; ++g) for (int g = 0; g < GENDER_MAX; ++g)
{ {
int listidx = PlayerClassLookups[classidx].ListIndex[0]; int listidx = PlayerClassLookups[classidx].ListIndex[0];
if (listidx != 0xffff) if (listidx != 0xffff)
@ -2178,7 +2179,7 @@ CCMD (playersounds)
for (i = 0; i < PlayerClassLookups.Size(); ++i) for (i = 0; i < PlayerClassLookups.Size(); ++i)
{ {
for (j = 0; j < 3; ++j) for (j = 0; j < GENDER_MAX; ++j)
{ {
if ((l = PlayerClassLookups[i].ListIndex[j]) != 0xffff) if ((l = PlayerClassLookups[i].ListIndex[j]) != 0xffff)
{ {

View file

@ -28,7 +28,8 @@ of the following entries:
is only useful when playing Doom. is only useful when playing Doom.
Gender (opt) The gender to use for deciding which player sounds Gender (opt) The gender to use for deciding which player sounds
to use for sounds not defined in the [Sounds] section. to use for sounds not defined in the [Sounds] section.
Can be male, female, or cyborg. The default is male. Can be male, female, neutral or cyborg.
The default is male.
ColorRange (opt) The range of palette entries to recolor to match ColorRange (opt) The range of palette entries to recolor to match
the player's color. Specified as <first>,<last>. the player's color. Specified as <first>,<last>.
For Doom, this defaults to 112,127. For Heretic, For Doom, this defaults to 112,127. For Heretic,

View file

@ -2317,7 +2317,8 @@ OPTVAL_ON = "On";
OPTVAL_AUTO = "Auto"; OPTVAL_AUTO = "Auto";
OPTVAL_MALE = "Male"; OPTVAL_MALE = "Male";
OPTVAL_FEMALE = "Female"; OPTVAL_FEMALE = "Female";
OPTVAL_OTHER = "Robotic"; OPTVAL_NEUTRAL = "Neutral";
OPTVAL_OTHER = "Object";
OPTVAL_UPPERLEFT = "Upper left"; OPTVAL_UPPERLEFT = "Upper left";
OPTVAL_UPPERRIGHT = "Upper right"; OPTVAL_UPPERRIGHT = "Upper right";
OPTVAL_LOWERLEFT = "Lower left"; OPTVAL_LOWERLEFT = "Lower left";

View file

@ -368,7 +368,8 @@ OptionValue "Gender"
{ {
0, "$OPTVAL_MALE" 0, "$OPTVAL_MALE"
1, "$OPTVAL_FEMALE" 1, "$OPTVAL_FEMALE"
2, "$OPTVAL_OTHER" 2, "$OPTVAL_NEUTRAL"
3, "$OPTVAL_OTHER"
} }
ListMenu "PlayerMenu" ListMenu "PlayerMenu"

View file

@ -1366,6 +1366,14 @@ enum EPlayerState
PST_GONE // Player has left the game PST_GONE // Player has left the game
} }
enum EPlayerGender
{
GENDER_MALE,
GENDER_FEMALE,
GENDER_NEUTRAL,
GENDER_OTHER
}
struct PlayerInfo native play // this is what internally is known as player_t struct PlayerInfo native play // this is what internally is known as player_t
{ {
// technically engine constants but the only part of the playsim using them is the player. // technically engine constants but the only part of the playsim using them is the player.