diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index 9d7351bac..845131706 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -159,6 +159,7 @@ static Lock *locks[256]; // all valid locks static bool keysdone=false; // have the locks been initialized? static int currentnumber; // number to be assigned to next key static bool ignorekey; // set to true when the current lock is not being used +static TArray KeyTypes; // List of all keys sorted by lock. static void ClearLocks(); @@ -406,6 +407,52 @@ static void ClearLocks() keysdone = false; } +//--------------------------------------------------------------------------- +// +// create a sorted list of the defined keys so +// this doesn't have to be done each frame +// +// For use by the HUD and statusbar code to get a consistent order. +// +//--------------------------------------------------------------------------- + +static int ktcmp(const void * a, const void * b) +{ + auto key1 = GetDefaultByType(*(PClassActor **)a); + auto key2 = GetDefaultByType(*(PClassActor **)b); + return key1->special1 - key2->special1; +} + +static void CreateSortedKeyList() +{ + TArray UnassignedKeyTypes; + KeyTypes.Clear(); + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++) + { + PClassActor *ti = PClassActor::AllActorClasses[i]; + auto kt = PClass::FindActor(NAME_Key); + + if (ti->IsDescendantOf(kt)) + { + AInventory *key = (AInventory*)(GetDefaultByType(ti)); + + if (key->Icon.isValid() && key->special1 > 0) + { + KeyTypes.Push(ti); + } + else + { + UnassignedKeyTypes.Push(ti); + } + } + } + if (KeyTypes.Size()) + { + qsort(&KeyTypes[0], KeyTypes.Size(), sizeof(KeyTypes[0]), ktcmp); + } + KeyTypes.Append(UnassignedKeyTypes); +} + //=========================================================================== // // P_InitKeyMessages @@ -440,6 +487,7 @@ void P_InitKeyMessages() } sc.Close(); } + CreateSortedKeyList(); keysdone = true; } @@ -464,7 +512,7 @@ void P_DeinitKeyMessages() // //=========================================================================== -bool P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet) +int P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet) { const char *failtext = NULL; FSoundID *failsound; @@ -521,15 +569,6 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet) return false; } -DEFINE_ACTION_FUNCTION(AActor, CheckKeys) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(locknum); - PARAM_BOOL(remote); - PARAM_BOOL(quiet); - ACTION_RETURN_BOOL(P_CheckKeys(self, locknum, remote, quiet)); -} - //========================================================================== // // These functions can be used to get color information for @@ -562,3 +601,15 @@ int P_GetMapColorForKey (AInventory * key) } return 0; } + + +int P_GetKeyTypeCount() +{ + return KeyTypes.Size(); +} + +PClassActor *P_GetKeyType(int num) +{ + if ((unsigned)num >= KeyTypes.Size()) return nullptr; + return KeyTypes[num]; +} diff --git a/src/g_inventory/a_keys.h b/src/g_inventory/a_keys.h index 05eff1189..14f6625a5 100644 --- a/src/g_inventory/a_keys.h +++ b/src/g_inventory/a_keys.h @@ -3,11 +3,14 @@ class AActor; class AInventory; +class PClassActor; -bool P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet = false); +int P_CheckKeys (AActor *owner, int keynum, bool remote, bool quiet = false); void P_InitKeyMessages (); void P_DeinitKeyMessages (); int P_GetMapColorForLock (int lock); int P_GetMapColorForKey (AInventory *key); +int P_GetKeyTypeCount(); +PClassActor *P_GetKeyType(int num); #endif diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 252ec8585..361e3ee4a 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -118,6 +118,7 @@ static FTexture * healthpic; // Health icon static FTexture * berserkpic; // Berserk icon (Doom only) static FTexture * fragpic; // Frags icon static FTexture * invgems[2]; // Inventory arrows +static FTextureID tnt1a0; // We need this to check for empty sprites. static int hudwidth, hudheight; // current width/height for HUD display static int statspace; @@ -165,6 +166,7 @@ static void DrawImageToBox(FTexture * tex, int x, int y, int w, int h, double tr // Draws a text but uses a fixed width for all characters // //--------------------------------------------------------------------------- +double GetBottomAlignOffset(FFont *font, int c); static void DrawHudText(FFont *font, int color, char * text, int x, int y, double trans = 0.75) { @@ -174,20 +176,15 @@ static void DrawHudText(FFont *font, int color, char * text, int x, int y, doubl x+=zerowidth/2; for(int i=0;text[i];i++) { - int width; - FTexture *texc = font->GetChar(text[i], &width); - if (texc != NULL) - { - double offset = texc->GetScaledTopOffsetDouble() - - tex_zero->GetScaledTopOffsetDouble() - + tex_zero->GetScaledHeightDouble(); + int width = font->GetCharWidth(text[i]); + double offset = GetBottomAlignOffset(font, text[i]); + + screen->DrawChar(font, color, x, y, text[i], + DTA_KeepRatio, true, + DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, + DTA_LeftOffset, width/2, DTA_TopOffsetF, offset, + /*DTA_CenterBottomOffset, 1,*/ TAG_DONE); - screen->DrawChar(font, color, x, y, text[i], - DTA_KeepRatio, true, - DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, - DTA_LeftOffset, width/2, DTA_TopOffsetF, offset, - /*DTA_CenterBottomOffset, 1,*/ TAG_DONE); - } x += zerowidth; } } @@ -367,53 +364,6 @@ static void DrawArmor(AInventory * barmor, AInventory * harmor, int x, int y) // //=========================================================================== -//--------------------------------------------------------------------------- -// -// create a sorted list of the defined keys so -// this doesn't have to be done each frame -// -//--------------------------------------------------------------------------- -static TArray KeyTypes, UnassignedKeyTypes; - -static int ktcmp(const void * a, const void * b) -{ - auto key1 = GetDefaultByType ( *(PClassActor **)a ); - auto key2 = GetDefaultByType ( *(PClassActor **)b ); - return key1->special1 - key2->special1; -} - -static void SetKeyTypes() -{ - for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++) - { - PClassActor *ti = PClassActor::AllActorClasses[i]; - auto kt = PClass::FindActor(NAME_Key); - - if (ti->IsDescendantOf(kt)) - { - AInventory *key = (AInventory*)(GetDefaultByType(ti)); - - if (key->Icon.isValid() && key->special1 > 0) - { - KeyTypes.Push(ti); - } - else - { - UnassignedKeyTypes.Push(ti); - } - } - } - if (KeyTypes.Size()) - { - qsort(&KeyTypes[0], KeyTypes.Size(), sizeof(KeyTypes[0]), ktcmp); - } - else - { - // Don't leave the list empty - KeyTypes.Push(PClass::FindActor(NAME_Key)); - } -} - //--------------------------------------------------------------------------- // // Draw one key @@ -443,7 +393,8 @@ static void DrawOneKey(int xo, int & x, int & y, int & c, AInventory * inv) { spritedef_t * sprdef = &sprites[state->sprite]; spriteframe_t * sprframe = &SpriteFrames[sprdef->spriteframes + state->GetFrame()]; - icon = sprframe->Texture[0]; + if (sprframe->Texture[0] != tnt1a0) + icon = sprframe->Texture[0]; } } if (icon.isNull()) icon = inv->Icon; @@ -472,26 +423,15 @@ static int DrawKeys(player_t * CPlayer, int x, int y) { int yo=y; int xo=x; - int i; int c=0; AInventory *inv; if (!deathmatch) { - if (KeyTypes.Size() == 0) SetKeyTypes(); - - // First all keys that are assigned to locks (in reverse order of definition) - for (i = KeyTypes.Size()-1; i >= 0; i--) + int i = P_GetKeyTypeCount(); + for(i--; i >= 0; i--) { - if ((inv = CPlayer->mo->FindInventory(KeyTypes[i]))) - { - DrawOneKey(xo, x, y, c, inv); - } - } - // And now the rest - for (i = UnassignedKeyTypes.Size()-1; i >= 0; i--) - { - if ((inv = CPlayer->mo->FindInventory(UnassignedKeyTypes[i]))) + if ((inv = CPlayer->mo->FindInventory(P_GetKeyType(i)))) { DrawOneKey(xo, x, y, c, inv); } @@ -666,78 +606,6 @@ static int DrawAmmo(player_t *CPlayer, int x, int y) } -//--------------------------------------------------------------------------- -// -// Weapons List -// -//--------------------------------------------------------------------------- -FTextureID GetInventoryIcon(AInventory *item, uint32_t flags, bool *applyscale=NULL) // This function is also used by SBARINFO -{ - if (applyscale != NULL) - { - *applyscale = false; - } - - if (item == nullptr) return FNullTextureID(); - - FTextureID picnum, AltIcon = item->AltHUDIcon; - FState * state=NULL, *ReadyState; - - picnum.SetNull(); - if (flags & DI_ALTICONFIRST) - { - if (!(flags & DI_SKIPALTICON) && AltIcon.isValid()) - picnum = AltIcon; - else if (!(flags & DI_SKIPICON)) - picnum = item->Icon; - } - else - { - if (!(flags & DI_SKIPICON) && item->Icon.isValid()) - picnum = item->Icon; - else if (!(flags & DI_SKIPALTICON)) - picnum = AltIcon; - } - - if (!picnum.isValid()) //isNull() is bad for checking, because picnum could be also invalid (-1) - { - if (!(flags & DI_SKIPSPAWN) && item->SpawnState && item->SpawnState->sprite!=0) - { - state = item->SpawnState; - - if (applyscale != NULL && !(flags & DI_FORCESCALE)) - { - *applyscale = true; - } - } - // no spawn state - now try the ready state if it's weapon - else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(NAME_Weapon) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0) - { - state = ReadyState; - } - if (state && (unsigned)state->sprite < (unsigned)sprites.Size ()) - { - spritedef_t * sprdef = &sprites[state->sprite]; - spriteframe_t * sprframe = &SpriteFrames[sprdef->spriteframes + state->GetFrame()]; - - picnum = sprframe->Texture[0]; - } - } - return picnum; -} - -DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetInventoryIcon) -{ - PARAM_PROLOGUE; - PARAM_OBJECT(item, AInventory); - PARAM_INT(flags); - bool applyscale; - FTextureID icon = GetInventoryIcon(item, flags, &applyscale); - if (numret >= 1) ret[0].SetInt(icon.GetIndex()); - if (numret >= 2) ret[1].SetInt(applyscale); - return MIN(numret, 2); -} - static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AInventory * weapon) { double trans; @@ -1265,12 +1133,10 @@ void HUD_InitHud() invgems[0] = TexMan.FindTexture("INVGEML1"); invgems[1] = TexMan.FindTexture("INVGEMR1"); + tnt1a0 = TexMan.CheckForTexture("TNT1A0", ETextureType::Sprite); fragpic = TexMan.FindTexture("HU_FRAGS"); // Sadly, I don't have anything usable for this. :( - KeyTypes.Clear(); - UnassignedKeyTypes.Clear(); - statspace = SmallFont->StringWidth("Ac:"); diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 5e0aa01f3..326a36028 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -498,7 +498,7 @@ void ST_Clear(); void ST_CreateStatusBar(bool bTitleLevel); extern FTexture *CrosshairImage; -FTextureID GetInventoryIcon(AInventory *item, uint32_t flags, bool *applyscale); +FTextureID GetInventoryIcon(AInventory *item, uint32_t flags, bool *applyscale = nullptr); enum DI_Flags diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 54b48ee3f..c8bd2ecc3 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -2202,3 +2202,75 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetMugshot) ACTION_RETURN_INT(tex ? tex->id.GetIndex() : -1); } +//--------------------------------------------------------------------------- +// +// Weapons List +// +//--------------------------------------------------------------------------- +FTextureID GetInventoryIcon(AInventory *item, uint32_t flags, bool *applyscale) +{ + if (applyscale != NULL) + { + *applyscale = false; + } + + if (item == nullptr) return FNullTextureID(); + + FTextureID picnum, Icon = item->Icon, AltIcon = item->AltHUDIcon; + FState * state = NULL, *ReadyState; + + picnum.SetNull(); + if (flags & DI_ALTICONFIRST) + { + if (!(flags & DI_SKIPALTICON) && AltIcon.isValid()) + picnum = AltIcon; + else if (!(flags & DI_SKIPICON)) + picnum = Icon; + } + else + { + if (!(flags & DI_SKIPICON) && item->Icon.isValid()) + picnum = Icon; + else if (!(flags & DI_SKIPALTICON)) + picnum = AltIcon; + } + + if (!picnum.isValid()) //isNull() is bad for checking, because picnum could be also invalid (-1) + { + if (!(flags & DI_SKIPSPAWN) && item->SpawnState && item->SpawnState->sprite != 0) + { + state = item->SpawnState; + + if (applyscale != NULL && !(flags & DI_FORCESCALE)) + { + *applyscale = true; + } + } + // no spawn state - now try the ready state if it's weapon + else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(NAME_Weapon) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite != 0) + { + state = ReadyState; + } + if (state && (unsigned)state->sprite < (unsigned)sprites.Size()) + { + spritedef_t * sprdef = &sprites[state->sprite]; + spriteframe_t * sprframe = &SpriteFrames[sprdef->spriteframes + state->GetFrame()]; + + picnum = sprframe->Texture[0]; + } + } + return picnum; +} + +DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetInventoryIcon) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(item, AInventory); + PARAM_INT(flags); + bool applyscale; + FTextureID icon = GetInventoryIcon(item, flags, &applyscale); + if (numret >= 1) ret[0].SetInt(icon.GetIndex()); + if (numret >= 2) ret[1].SetInt(applyscale); + return MIN(numret, 2); +} + diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index e353eaa44..a7de8b2b9 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -35,6 +35,7 @@ #include "p_local.h" #include "v_font.h" #include "gstrings.h" +#include "a_keys.h" //===================================================================================== // @@ -1578,6 +1579,34 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_PlaySound, A_PlaySound) return 0; } +DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckKeys, P_CheckKeys) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(locknum); + PARAM_BOOL(remote); + PARAM_BOOL(quiet); + ACTION_RETURN_BOOL(P_CheckKeys(self, locknum, remote, quiet)); +} + + +//===================================================================================== +// +// Key exports +// +//===================================================================================== + +DEFINE_ACTION_FUNCTION_NATIVE(AKey, GetKeyTypeCount, P_GetKeyTypeCount) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(P_GetKeyTypeCount()); +} + +DEFINE_ACTION_FUNCTION_NATIVE(AKey, GetKeyType, P_GetKeyType) +{ + PARAM_PROLOGUE; + PARAM_INT(num); + ACTION_RETURN_POINTER(P_GetKeyType(num)); +} DEFINE_FIELD_X(Sector, sector_t, floorplane) DEFINE_FIELD_X(Sector, sector_t, ceilingplane) diff --git a/wadsrc/static/zscript/inventory/inv_misc.txt b/wadsrc/static/zscript/inventory/inv_misc.txt index ce4bf805b..4761408b3 100644 --- a/wadsrc/static/zscript/inventory/inv_misc.txt +++ b/wadsrc/static/zscript/inventory/inv_misc.txt @@ -36,6 +36,9 @@ class Key : Inventory Inventory.InterHubAmount 0; Inventory.PickupSound "misc/k_pkup"; } + + static native clearscope int GetKeyTypeCount(); + static native clearscope class GetKeyType(int index); override bool HandlePickup (Inventory item) {