diff --git a/src/d_main.cpp b/src/d_main.cpp index e91c2ccaa..e0cbcbefa 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2707,6 +2707,8 @@ void D_DoomMain (void) // delete all data that cannot be left until reinitialization V_ClearFonts(); // must clear global font pointers + ColorSets.Clear(); + PainFlashes.Clear(); R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. gameinfo.~gameinfo_t(); new (&gameinfo) gameinfo_t; // Reset gameinfo diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index d3ce8c943..62beb5460 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -156,7 +156,7 @@ int D_PlayerClassToInt (const char *classname) { for (unsigned int i = 0; i < PlayerClasses.Size (); ++i) { - PClassPlayerPawn *type = PlayerClasses[i].Type; + auto type = PlayerClasses[i].Type; if (type->DisplayName.IsNotEmpty() && stricmp(type->DisplayName, classname) == 0) { @@ -180,7 +180,7 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet if (players[player].mo != NULL) { - colorset = players[player].mo->GetClass()->GetColorSet(info->GetColorSet()); + colorset = GetColorSet(players[player].mo->GetClass(), info->GetColorSet()); } if (colorset != NULL) { diff --git a/src/d_player.h b/src/d_player.h index f6009edec..8a5415bc6 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -66,8 +66,11 @@ struct FPlayerColorSet ExtraRange Extra[6]; }; -typedef TMap FPlayerColorSetMap; -typedef TMap PainFlashList; +typedef TArray> PainFlashList; +typedef TArray> ColorSetList; + +extern PainFlashList PainFlashes; +extern ColorSetList ColorSets; class PClassPlayerPawn : public PClassActor { @@ -76,14 +79,8 @@ protected: public: PClassPlayerPawn(); virtual void DeriveData(PClass *newclass); - void EnumColorSets(TArray *out); - FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); } - void SetPainFlash(FName type, PalEntry color); - bool GetPainFlash(FName type, PalEntry *color) const; FString DisplayName; // Display name (used in menus, etc.) - FPlayerColorSetMap ColorSets; - PainFlashList PainFlashes; }; FString GetPrintableDisplayName(PClassPlayerPawn *cls); @@ -541,12 +538,16 @@ public: // Make sure that a state is properly set after calling this unless // you are 100% sure the context already implies the layer exists. DPSprite *GetPSprite(PSPLayers layer); + + bool GetPainFlash(FName type, PalEntry *color) const; }; // Bookkeeping on players - state. extern player_t players[MAXPLAYERS]; void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale); +void EnumColorSets(PClassActor *pc, TArray *out); +FPlayerColorSet *GetColorSet(PClassActor *pc, int setnum); inline void AActor::SetFriendPlayer(player_t *player) { diff --git a/src/doomtype.h b/src/doomtype.h index 11e4f96e2..c88ec842d 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -41,6 +41,8 @@ #endif #include +#include +#include #include "tarray.h" #include "name.h" #include "zstring.h" diff --git a/src/g_pch.h b/src/g_pch.h index 2c3676f5a..e5653796b 100644 --- a/src/g_pch.h +++ b/src/g_pch.h @@ -20,3 +20,4 @@ #include #include #include +#include diff --git a/src/menu/playerdisplay.cpp b/src/menu/playerdisplay.cpp index 821c2ea70..ba99aba36 100644 --- a/src/menu/playerdisplay.cpp +++ b/src/menu/playerdisplay.cpp @@ -435,7 +435,7 @@ void DListMenuItemPlayerDisplay::UpdateTranslation() if (mPlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, mPlayerClass->Type->GetColorSet(PlayerColorset), + R_GetPlayerTranslation(PlayerColor, GetColorSet(mPlayerClass->Type, PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 7116608b3..4126bc80b 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -680,7 +680,7 @@ void DPlayerMenu::UpdateTranslation() if (PlayerClass != NULL) { PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); - R_GetPlayerTranslation(PlayerColor, PlayerClass->Type->GetColorSet(PlayerColorset), + R_GetPlayerTranslation(PlayerColor, GetColorSet(PlayerClass->Type, PlayerColorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } } @@ -749,11 +749,11 @@ void DPlayerMenu::UpdateColorsets() if (li != NULL) { int sel = 0; - PlayerClass->Type->EnumColorSets(&PlayerColorSets); + EnumColorSets(PlayerClass->Type, &PlayerColorSets); li->SetString(0, "Custom"); for(unsigned i=0;iType->GetColorSet(PlayerColorSets[i]); + FPlayerColorSet *colorset = GetColorSet(PlayerClass->Type, PlayerColorSets[i]); li->SetString(i+1, colorset->Name); } int mycolorset = players[consoleplayer].userinfo.GetColorSet(); diff --git a/src/p_user.cpp b/src/p_user.cpp index 98221de1f..161d15121 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -84,6 +84,9 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO P_PredictionLerpReset(); } +ColorSetList ColorSets; +PainFlashList PainFlashes; + struct PredictPos { int gametic; @@ -551,23 +554,38 @@ void PClassPlayerPawn::DeriveData(PClass *newclass) PClassPlayerPawn *newp = static_cast(newclass); newp->DisplayName = DisplayName; - newp->ColorSets = ColorSets; } +//=========================================================================== +// +// EnumColorsets +// +// Only used by the menu so it doesn't really matter that it's a bit +// inefficient. +// +//=========================================================================== + static int intcmp(const void *a, const void *b) { return *(const int *)a - *(const int *)b; } -void PClassPlayerPawn::EnumColorSets(TArray *out) +void EnumColorSets(PClassActor *cls, TArray *out) { - out->Clear(); - FPlayerColorSetMap::Iterator it(ColorSets); - FPlayerColorSetMap::Pair *pair; + TArray deleteds; - while (it.NextPair(pair)) + out->Clear(); + for (int i = ColorSets.Size() - 1; i >= 0; i--) { - out->Push(pair->Key); + if (std::get<0>(ColorSets[i])->IsAncestorOf(cls)) + { + int v = std::get<1>(ColorSets[i]); + if (out->Find(v) == out->Size() && deleteds.Find(v) == deleteds.Size()) + { + if (std::get<2>(ColorSets[i]).Name == NAME_None) deleteds.Push(v); + else out->Push(v); + } + } } qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); } @@ -577,20 +595,41 @@ void PClassPlayerPawn::EnumColorSets(TArray *out) // //========================================================================== -bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const +FPlayerColorSet *GetColorSet(PClassActor *cls, int setnum) { - const PClassPlayerPawn *info = this; - - while (info != NULL) + for (int i = ColorSets.Size() - 1; i >= 0; i--) { - const PalEntry *flash = info->PainFlashes.CheckKey(type); - if (flash != NULL) + if (std::get<1>(ColorSets[i]) == setnum && + std::get<0>(ColorSets[i])->IsAncestorOf(cls)) { - *color = *flash; + auto c = &std::get<2>(ColorSets[i]); + return c->Name != NAME_None ? c : nullptr; + } + } + return nullptr; +} + +//========================================================================== +// +// +//========================================================================== + +bool player_t::GetPainFlash(FName type, PalEntry *color) const +{ + PClass *info = mo->GetClass(); + + // go backwards through the list and return the first item with a + // matching damage type for an ancestor of our class. + // This will always return the best fit because any parent class + // must be processed before its children. + for (int i = PainFlashes.Size() - 1; i >= 0; i--) + { + if (std::get<1>(PainFlashes[i]) == type && + std::get<0>(PainFlashes[i])->IsAncestorOf(info)) + { + *color = std::get<2>(PainFlashes[i]); return true; } - // Try parent class - info = dyn_cast(info->ParentClass); } return false; } @@ -3238,8 +3277,6 @@ DEFINE_FIELD(APlayerPawn, ColorRangeStart) DEFINE_FIELD(APlayerPawn, ColorRangeEnd) DEFINE_FIELD(PClassPlayerPawn, DisplayName) -DEFINE_FIELD(PClassPlayerPawn, ColorSets) -DEFINE_FIELD(PClassPlayerPawn, PainFlashes) DEFINE_FIELD_X(PlayerInfo, player_t, mo) DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 7f363b623..33d97dccf 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -69,6 +69,7 @@ #include "backend/vmbuilder.h" #include "a_keys.h" #include "g_levellocals.h" +#include "d_player.h" //========================================================================== // @@ -2386,8 +2387,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl } else { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Insert(setnum, color); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2413,8 +2413,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) } else if (color.Lump >= 0) { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Insert(setnum, color); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2431,8 +2430,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn) } else { - assert(info->IsKindOf(RUNTIME_CLASS(PClassPlayerPawn))); - static_cast(info)->ColorSets.Remove(setnum); + FPlayerColorSet color; + memset(&color, 0, sizeof(color)); + ColorSets.Push(std::make_tuple(info, setnum, color)); } } @@ -2666,7 +2666,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, Cfs, PlayerPawn) PROP_STRING_PARM(type, 3); color.a = BYTE(255 * clamp(a, 0.f, 1.f)); - static_cast(info)->PainFlashes.Insert(type, color); + PainFlashes.Push(std::make_tuple(info, type, color)); } } diff --git a/src/v_blend.cpp b/src/v_blend.cpp index ffc16cd5c..41e6fe7ff 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -123,7 +123,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int } PalEntry painFlash = CPlayer->mo->DamageFade; - CPlayer->mo->GetClass()->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); + CPlayer->GetPainFlash(CPlayer->mo->DamageTypeReceived, &painFlash); if (painFlash.a != 0) {