diff --git a/src/bbannouncer.cpp b/src/bbannouncer.cpp index 144528cd7..80de8b979 100644 --- a/src/bbannouncer.cpp +++ b/src/bbannouncer.cpp @@ -59,7 +59,7 @@ struct SoundAndString // 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); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -266,7 +266,7 @@ bool AnnounceKill (AActor *killer, AActor *killee) { char assembled[1024]; - SexMessage (message, assembled, killee->player->userinfo.GetGender(), + PronounMessage (message, assembled, killee->player->userinfo.GetGender(), killee->player->userinfo.GetName(), killerName); Printf (PRINT_MEDIUM, "%s\n", assembled); } @@ -298,7 +298,7 @@ bool AnnounceTelefrag (AActor *killer, AActor *killee) { 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()); Printf (PRINT_MEDIUM, "%s\n", assembled); } diff --git a/src/d_netinf.h b/src/d_netinf.h index c5c82f65b..34df4bcea 100644 --- a/src/d_netinf.h +++ b/src/d_netinf.h @@ -36,8 +36,17 @@ #include "c_cvars.h" +enum +{ + GENDER_MALE, + GENDER_FEMALE, + GENDER_NEUTER, + GENDER_OBJECT, + GENDER_MAX +}; + int D_GenderToInt (const char *gender); -extern const char *GenderNames[3]; +extern const char *GenderNames[GENDER_MAX]; int D_PlayerClassToInt (const char *classname); diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index ef68ebf4e..b058d92d0 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -83,7 +83,7 @@ enum INFO_ClassicFlight, }; -const char *GenderNames[3] = { "male", "female", "other" }; +const char *GenderNames[GENDER_MAX] = { "male", "female", "neutral", "other" }; // Replace \ with %/ and % with %% 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) { - if (!stricmp (gender, "female")) + if (gender[0] == 'f') 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; else - return GENDER_MALE; + return GENDER_OBJECT; } int D_PlayerClassToInt (const char *classname) @@ -726,7 +728,8 @@ void D_WriteUserInfoStrings (int pnum, uint8_t **stream, bool compact) case NAME_Gender: *stream += sprintf(*((char **)stream), "\\%s", *static_cast(pair->Value) == GENDER_FEMALE ? "female" : - *static_cast(pair->Value) == GENDER_NEUTER ? "other" : "male"); + *static_cast(pair->Value) == GENDER_MALE ? "male" : + *static_cast(pair->Value) == GENDER_NEUTER ? "neutral" : "other"); break; case NAME_PlayerClass: diff --git a/src/d_player.h b/src/d_player.h index ee1418f57..2a8daa4f9 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -34,6 +34,8 @@ #include "a_weapons.h" +#include "d_netinf.h" + // The player data structure depends on a number // of other structs: items (internal inventory), // animation states (closely tied to the sprites @@ -261,13 +263,6 @@ public: extern TArray PlayerClasses; // User info (per-player copies of each CVAR_USERINFO cvar) -enum -{ - GENDER_MALE, - GENDER_FEMALE, - GENDER_NEUTER -}; - struct userinfo_t : TMap { ~userinfo_t(); diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 9a3ea12e6..1bfed5fc6 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -440,7 +440,8 @@ void FGLRenderState::SetStencil(int offs, int op, int flags) glStencilOp(GL_KEEP, GL_KEEP, op2gl[op]); // this stage doesn't modify the stencil bool cmon = !(flags & SF_ColorMaskOff); - glColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer + bool cmalpha = cmon || (flags & SF_ColorMaskAlpha); + glColorMask(cmon, cmon, cmon, cmalpha); // don't write to the graphics buffer glDepthMask(!(flags & SF_DepthMaskOff)); } diff --git a/src/hwrenderer/data/buffers.h b/src/hwrenderer/data/buffers.h index d179d5447..9707a6eea 100644 --- a/src/hwrenderer/data/buffers.h +++ b/src/hwrenderer/data/buffers.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + // The low level code needs to know which attributes exist. // OpenGL needs to change the state of all of them per buffer binding. // VAOs are mostly useless for this because they lump buffer and binding state together which the model code does not want. @@ -75,4 +78,4 @@ public: virtual void BindRange(size_t start, size_t length) = 0; virtual void BindBase() = 0; -}; \ No newline at end of file +}; diff --git a/src/hwrenderer/scene/hw_portal.cpp b/src/hwrenderer/scene/hw_portal.cpp index dc2c8f4fb..6426e4213 100644 --- a/src/hwrenderer/scene/hw_portal.cpp +++ b/src/hwrenderer/scene/hw_portal.cpp @@ -301,7 +301,7 @@ void HWPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestenci state.EnableTexture(false); state.SetRenderStyle(STYLE_Source); - state.SetStencil(0, SOP_Keep, SF_ColorMaskOff); + state.SetStencil(0, SOP_Keep, SF_ColorMaskOff | SF_ColorMaskAlpha); // SSAO needs the alpha channel as a marker. if (needdepth) state.Clear(CT_Depth); state.SetDepthRange(0, 1); state.SetDepthFunc(DF_LEqual); @@ -946,8 +946,8 @@ void HWEEHorizonPortal::DrawContents(HWDrawInfo *di, FRenderState &state) { GLSkyInfo skyinfo; skyinfo.init(sector->sky, 0); - //GLSkyPortal sky(mState, &skyinfo, true); - //sky.DrawContents(di, state); + HWSkyPortal sky(screen->mSkyData, mState, &skyinfo, true); + sky.DrawContents(di, state); } if (sector->GetTexture(sector_t::ceiling) != skyflatnum) { diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index 9f2a848b9..99bded7e2 100644 --- a/src/hwrenderer/scene/hw_renderstate.h +++ b/src/hwrenderer/scene/hw_renderstate.h @@ -57,6 +57,7 @@ enum EStencilFlags SF_AllOn = 0, SF_ColorMaskOff = 1, SF_DepthMaskOff = 2, + SF_ColorMaskAlpha = 4, // hack value for SSAO }; enum EStencilOp @@ -485,21 +486,21 @@ public: virtual void DrawIndexed(int dt, int index, int count, bool apply = true) = 0; // Immediate render state change commands. These only change infrequently and should not clutter the render state. - virtual bool SetDepthClamp(bool on) = 0; - virtual void SetDepthMask(bool on) = 0; - virtual void SetDepthFunc(int func) = 0; - virtual void SetDepthRange(float min, float max) = 0; - virtual void EnableDrawBufferAttachments(bool on) = 0; - virtual void SetStencil(int offs, int op, int flags) = 0; - virtual void SetCulling(int mode) = 0; - virtual void EnableClipDistance(int num, bool state) = 0; - virtual void Clear(int targets) = 0; - virtual void EnableStencil(bool on) = 0; - virtual void SetScissor(int x, int y, int w, int h) = 0; - virtual void SetViewport(int x, int y, int w, int h) = 0; - virtual void EnableDepthTest(bool on) = 0; - virtual void EnableMultisampling(bool on) = 0; - virtual void EnableLineSmooth(bool on) = 0; + virtual bool SetDepthClamp(bool on) = 0; // Deactivated only by skyboxes. + virtual void SetDepthMask(bool on) = 0; // Used by decals and indirectly by portal setup. + virtual void SetDepthFunc(int func) = 0; // Used by models, portals and mirror surfaces. + virtual void SetDepthRange(float min, float max) = 0; // Used by portal setup. + virtual void EnableDrawBufferAttachments(bool on) = 0; // Used by fog boundary drawer. + virtual void SetStencil(int offs, int op, int flags) = 0; // Used by portal setup and render hacks. + virtual void SetCulling(int mode) = 0; // Used by model drawer only. + virtual void EnableClipDistance(int num, bool state) = 0; // Use by sprite sorter for vertical splits. + virtual void Clear(int targets) = 0; // not used during normal rendering + virtual void EnableStencil(bool on) = 0; // always on for 3D, always off for 2D + virtual void SetScissor(int x, int y, int w, int h) = 0; // constant for 3D, changes for 2D + virtual void SetViewport(int x, int y, int w, int h) = 0; // constant for all 3D and all 2D + virtual void EnableDepthTest(bool on) = 0; // used by 2D, portals and render hacks. + virtual void EnableMultisampling(bool on) = 0; // only active for 2D + virtual void EnableLineSmooth(bool on) = 0; // constant setting for each 2D drawer operation }; diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 507470e57..973a49fdf 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -207,7 +207,13 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged) // only allow if the menu is active to prevent abuse. 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; } diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index ab7dce496..e1fea0c63 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -112,30 +112,34 @@ void P_TouchSpecialThing (AActor *special, AActor *toucher) // [RH] -// SexMessage: Replace parts of strings with gender-specific pronouns +// PronounMessage: Replace parts of strings with player-specific pronouns // // The following expansions are performed: -// %g -> he/she/it -// %h -> him/her/it -// %p -> his/her/its +// %g -> he/she/they/it +// %h -> him/her/them/it +// %p -> his/her/their/its +// %s -> his/hers/theirs/its +// %r -> he's/she's/they're/it's // %o -> other (victim) // %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" }, - { "she", "her", "her" }, - { "it", "it", "its" } + { "he", "him", "his", "his", "he's" }, + { "she", "her", "her", "hers", "she's" }, + { "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 }, - { 3, 3, 3 }, - { 2, 2, 3 } + { 2, 3, 3, 3, 4 }, + { 3, 3, 3, 4, 5 }, + { 4, 4, 5, 6, 7 }, + { 2, 2, 3, 4, 4 } }; - const char *subst = NULL; + const char *substitute = NULL; do { @@ -145,32 +149,34 @@ void SexMessage (const char *from, char *to, int gender, const char *victim, con } else { - int gendermsg = -1; + int grammarcase = -1; switch (from[1]) { - case 'g': gendermsg = 0; break; - case 'h': gendermsg = 1; break; - case 'p': gendermsg = 2; break; - case 'o': subst = victim; break; - case 'k': subst = killer; break; + case 'g': grammarcase = 0; break; // Subject + case 'h': grammarcase = 1; break; // Object + case 'p': grammarcase = 2; break; // Possessive Determiner + case 's': grammarcase = 3; break; // Possessive Pronoun + 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); - memcpy (to, subst, len); + size_t len = strlen (substitute); + memcpy (to, substitute, len); to += len; from++; - subst = NULL; + substitute = nullptr; } - else if (gendermsg < 0) + else if (grammarcase < 0) { *to++ = '%'; } else { - strcpy (to, genderstuff[gender][gendermsg]); - to += gendershift[gender][gendermsg]; + strcpy (to, pronouns[pronoun][grammarcase]); + to += pronounshift[pronoun][grammarcase]; from++; } } @@ -268,7 +274,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf if (message == NULL || strlen(message) <= 0) return; - SexMessage (message, gendermessage, self->player->userinfo.GetGender(), + PronounMessage (message, gendermessage, self->player->userinfo.GetGender(), self->player->userinfo.GetName(), attacker->player->userinfo.GetName()); Printf (PRINT_MEDIUM, "%s\n", gendermessage); } @@ -402,7 +408,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf player->fragcount--; if (deathmatch && player->spreecount >= 5 && cl_showsprees) { - SexMessage (GStrings("SPREEKILLSELF"), buff, + PronounMessage (GStrings("SPREEKILLSELF"), buff, player->userinfo.GetGender(), player->userinfo.GetName(), player->userinfo.GetName()); StatusBar->AttachMessage (Create(SmallFont, buff, @@ -460,7 +466,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf { if (!AnnounceSpreeLoss (this)) { - SexMessage (GStrings("SPREEOVER"), buff, player->userinfo.GetGender(), + PronounMessage (GStrings("SPREEOVER"), buff, player->userinfo.GetGender(), player->userinfo.GetName(), source->player->userinfo.GetName()); StatusBar->AttachMessage (Create (SmallFont, buff, 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)) { - SexMessage (spreemsg, buff, player->userinfo.GetGender(), + PronounMessage (spreemsg, buff, player->userinfo.GetGender(), player->userinfo.GetName(), source->player->userinfo.GetName()); StatusBar->AttachMessage (Create (SmallFont, buff, 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)) { - SexMessage (multimsg, buff, player->userinfo.GetGender(), + PronounMessage (multimsg, buff, player->userinfo.GetGender(), player->userinfo.GetName(), source->player->userinfo.GetName()); StatusBar->AttachMessage (Create (SmallFont, buff, 1.5f, 0.8f, 0, 0, CR_RED, 3.f, 0.5f), MAKE_ID('M','K','I','L')); diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index d5093fde6..f0ec171c6 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -80,7 +80,7 @@ struct FRandomSoundList struct FPlayerClassLookup { 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 @@ -1622,7 +1622,8 @@ static int S_AddPlayerClass (const char *name) FPlayerClassLookup lookup; 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); PlayerClassesIsSorted = false; @@ -1770,11 +1771,11 @@ static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid) { int g; - for (g = 0; g < 3 && listidx == 0xffff; ++g) + for (g = 0; g < GENDER_MAX && listidx == 0xffff; ++g) { listidx = PlayerClassLookups[classidx].ListIndex[g]; } - if (g == 3) + if (g == GENDER_MAX) { // No sounds defined at all for this class (can this happen?) if (classidx != DefPlayerClass) { @@ -1796,7 +1797,7 @@ static int S_LookupPlayerSound (int classidx, int gender, FSoundID refid) { // This sound is unavailable. if (ingender != 0) { // Try "male" - return S_LookupPlayerSound (classidx, 0, refid); + return S_LookupPlayerSound (classidx, GENDER_MALE, refid); } if (classidx != DefPlayerClass) { // Try the default class. @@ -1912,7 +1913,7 @@ bool S_AreSoundsEquivalent (AActor *actor, int id1, int id2) int S_FindSkinnedSound (AActor *actor, FSoundID refid) { const char *pclass; - int gender = GENDER_MALE; + int gender = 0; if (actor != NULL && actor->IsKindOf(RUNTIME_CLASS(APlayerPawn))) { @@ -2074,7 +2075,7 @@ void S_MarkPlayerSounds (const char *playerclass) { classidx = DefPlayerClass; } - for (int g = 0; g < 3; ++g) + for (int g = 0; g < GENDER_MAX; ++g) { int listidx = PlayerClassLookups[classidx].ListIndex[0]; if (listidx != 0xffff) @@ -2178,7 +2179,7 @@ CCMD (playersounds) 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) { diff --git a/src/skins.cpp b/src/skins.cpp index c3f5f0a4d..72b988a3a 100644 --- a/src/skins.cpp +++ b/src/skins.cpp @@ -28,7 +28,8 @@ of the following entries: is only useful when playing Doom. Gender (opt) The gender to use for deciding which player sounds 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 the player's color. Specified as ,. For Doom, this defaults to 112,127. For Heretic, diff --git a/src/swrenderer/line/r_renderdrawsegment.cpp b/src/swrenderer/line/r_renderdrawsegment.cpp index f21c9e79f..fbc18b0c6 100644 --- a/src/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/swrenderer/line/r_renderdrawsegment.cpp @@ -159,6 +159,9 @@ namespace swrenderer auto viewport = Thread->Viewport.get(); Clip3DFloors *clip3d = Thread->Clip3D.get(); + if (curline->sidedef->GetTexture(side_t::mid).isNull()) + return false; + FTexture *tex = TexMan(curline->sidedef->GetTexture(side_t::mid), true); if (i_compatflags & COMPATF_MASKEDMIDTEX) { diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 07c8eefaf..c5fe1da0a 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2317,7 +2317,8 @@ OPTVAL_ON = "On"; OPTVAL_AUTO = "Auto"; OPTVAL_MALE = "Male"; OPTVAL_FEMALE = "Female"; -OPTVAL_OTHER = "Robotic"; +OPTVAL_NEUTRAL = "Neutral"; +OPTVAL_OTHER = "Object"; OPTVAL_UPPERLEFT = "Upper left"; OPTVAL_UPPERRIGHT = "Upper right"; OPTVAL_LOWERLEFT = "Lower left"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 640b6186c..4bb577ac6 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -368,7 +368,8 @@ OptionValue "Gender" { 0, "$OPTVAL_MALE" 1, "$OPTVAL_FEMALE" - 2, "$OPTVAL_OTHER" + 2, "$OPTVAL_NEUTRAL" + 3, "$OPTVAL_OTHER" } ListMenu "PlayerMenu" diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index e7c05e7d6..dce27e106 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -1366,6 +1366,14 @@ enum EPlayerState 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 { // technically engine constants but the only part of the playsim using them is the player.