From 50dcf587f4ef5f8a5cb4e346ca705376345978e4 Mon Sep 17 00:00:00 2001 From: thebigMuh <81810641+thebigMuh@users.noreply.github.com> Date: Mon, 19 Apr 2021 02:59:20 +0200 Subject: [PATCH] Adding fancier XP bar (#1597) --- CMakeLists.txt | 2 + Packaging/resources/devilutionx.mpq | Bin 543285 -> 544364 bytes Source/control.cpp | 6 ++ Source/qol.cpp | 56 ++-------- Source/qol.h | 1 - Source/qol/common.cpp | 27 +++++ Source/qol/common.h | 23 +++++ Source/qol/xpbar.cpp | 154 ++++++++++++++++++++++++++++ Source/qol/xpbar.h | 18 ++++ Source/scrollrt.cpp | 1 + 10 files changed, 237 insertions(+), 51 deletions(-) create mode 100644 Source/qol/common.cpp create mode 100644 Source/qol/common.h create mode 100644 Source/qol/xpbar.cpp create mode 100644 Source/qol/xpbar.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 649be09e0..94e9b3cbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -294,6 +294,8 @@ set(devilutionx_SRCS Source/controls/modifier_hints.cpp Source/controls/plrctrls.cpp Source/controls/touch.cpp + Source/qol/common.cpp + Source/qol/xpbar.cpp Source/utils/console.cpp Source/utils/display.cpp Source/utils/file_util.cpp diff --git a/Packaging/resources/devilutionx.mpq b/Packaging/resources/devilutionx.mpq index 1a52d468d75fce1fa8be443124380cbf982f0b45..d62e01e30984c26032d3fbf4eaad92b20ce2b39d 100644 GIT binary patch delta 1196 zcmV;d1XKI9lp*Y#AstOnQ5qls003-G2mk;80|3lS2ms7Y2mlZO000Vs9fchMg&hKg z9Rr0O1ce<1g&hWk9S5}?2#833q2>ALzckg&8dPkx2#*!2mQ7bdW8-eTn(~@oh5-Q> zf`_B(N<}{8D9)mpr0eEmuH-@w6`+-O83pC-5OJXq4=nRex@B zBv*RNK7LH16n%vh>Drv|&F$&eC6O*WjVAR(sVdlvptsBoKp=%%TWce;RLitTQGh~N z%qp2ehah5l`c(s~rzbnJzfX6ssT!L+NiNrg&7s`{*(lq8+BrvfK^|4H6#Z2-tfdcE z(A0mR#Fkl0c;BQ5Fh@;)mw4%QYGFmWF}KdKa`;llZw-o`qL8sxZ$k1rQ4}X?&}9IdgN97I6A$o^TkB@{<&4#+o4!0a+g$=Sa6g`RwMK~NlGn^PD+?j zFeb*Rw#2o1$~;19TWw>WV4y%?n>?`ha@HyE_WRKyGrS6TLn;q{+_n5OPaZ+J3EuPc zZzk7uJJw5C3T9z}w(wpyHr!EqwS^p#4Qa-3IhU8nx|ShkG(Ug79N8NW3K|mw96iet zJxHWx1cy|*&5mL6jM>Sqem9!7InMS$7ND$8 zjvA~)7lJPT`RS$PLVl6Q5>@|*CMEQ>@6pCpA0|(FEFaB)_*b>b4yL*Z*t=>L>{_Oz z$W*A!ISljPLM#1^Y_HZJZ$1v_pbXk*BFG2tHrjfWb<$`W}UL7A}vhL-7F2#zrU{*@Jj}w*aBHx8|6zGfUbu&POf|kWmK&!DIvVc0ogF zD8HZ!h9@tTambwE()Mo%LaBKmu96tit=Jy8P=%C#jaV87Ef}K35}l~Q%ji?@JTBxe zc``}7FYqtE#`<_yNRQg zM94C4Wg$EqjNTEZCQGk5t1W&v^|I=*5CdluXU&mf7sa^fMpI*#8)vODE^28u7P|4d zUXwL1RV*>0nD%i0Bp*GKNdLHnlt>&C`dsf0S?1optugRvW4b8KYBB~Al6U_7AMg*C zrAP?iAZVm)w5k#bN$Av7l{FUX?Kp_1%7Mzh^+NshwY0tqpqHgd2#^p?3Z(BzhUjjB Kb5e$WVoXYAKrq$- delta 107 zcmaDeM{(;EMOoi~Kq&-0i3_!*|m1 L6VuQ5a!ddK^w%Rq diff --git a/Source/control.cpp b/Source/control.cpp index 46f07179e..4dc48d3af 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -17,6 +17,7 @@ #include "lighting.h" #include "minitext.h" #include "missiles.h" +#include "qol/xpbar.h" #include "stores.h" #include "towners.h" #include "trigs.h" @@ -1116,6 +1117,11 @@ void CheckPanelInfo() } if (MouseX > 190 + PANEL_LEFT && MouseX < 437 + PANEL_LEFT && MouseY > 4 + PANEL_TOP && MouseY < 33 + PANEL_TOP) pcursinvitem = CheckInvHLight(); + + if (CheckXPBarInfo()) { + panelflag = true; + pinfoflag = true; + } } /** diff --git a/Source/qol.cpp b/Source/qol.cpp index c7f2aa4a1..61392a225 100644 --- a/Source/qol.cpp +++ b/Source/qol.cpp @@ -8,6 +8,8 @@ #include "cursor.h" #include "DiabloUI/art_draw.h" #include "options.h" +#include "qol/common.h" +#include "qol/xpbar.h" namespace devilution { namespace { @@ -29,11 +31,6 @@ int GetTextWidth(const char *s) return l; } -void FastDrawHorizLine(CelOutputBuffer out, int x, int y, int width, BYTE col) -{ - memset(out.at(x, y), col, width); -} - void FastDrawVertLine(CelOutputBuffer out, int x, int y, int height, BYTE col) { BYTE *p = out.at(x, y); @@ -43,19 +40,14 @@ void FastDrawVertLine(CelOutputBuffer out, int x, int y, int height, BYTE col) } } -void FillRect(CelOutputBuffer out, int x, int y, int width, int height, BYTE col) -{ - for (int j = 0; j < height; j++) { - FastDrawHorizLine(out, x, y + j, width, col); - } -} - } // namespace void FreeQol() { delete qolArt; qolArt = nullptr; + + FreeXPBar(); } void InitQol() @@ -72,6 +64,8 @@ void InitQol() app_fatal("Failed to load UI resources. Is devilutionx.mpq accessible and up to date?"); } } + + InitXPBar(); } void DrawMonsterHealthBar(CelOutputBuffer out) @@ -152,45 +146,7 @@ void DrawMonsterHealthBar(CelOutputBuffer out) } } -void DrawXPBar(CelOutputBuffer out) -{ - if (!sgOptions.Gameplay.bExperienceBar) - return; - int barWidth = 306; - int barHeight = 5; - int yPos = gnScreenHeight - 9; // y position of xp bar - int xPos = (gnScreenWidth - barWidth) / 2 + 5; // x position of xp bar - int dividerHeight = 3; - int numDividers = 10; - int barColor = 198; - int emptyBarColor = 0; - int frameColor = 196; - bool space = true; // add 1 pixel separator on top/bottom of the bar - - PrintGameStr(out, xPos - 22, yPos + 6, "XP", COL_WHITE); - int charLevel = plr[myplr]._pLevel; - if (charLevel == MAXCHARLEVEL - 1) - return; - - int prevXp = ExpLvlsTbl[charLevel - 1]; - if (plr[myplr]._pExperience < prevXp) - return; - - Uint64 prevXpDelta_1 = plr[myplr]._pExperience - prevXp; - int prevXpDelta = ExpLvlsTbl[charLevel] - prevXp; - int visibleBar = barWidth * prevXpDelta_1 / prevXpDelta; - - FillRect(out, xPos, yPos, barWidth, barHeight, emptyBarColor); - FastDrawHorizLine(out, xPos - 1, yPos - 1, barWidth + 2, frameColor); - FastDrawHorizLine(out, xPos - 1, yPos + barHeight, barWidth + 2, frameColor); - FastDrawVertLine(out, xPos - 1, yPos - 1, barHeight + 2, frameColor); - FastDrawVertLine(out, xPos + barWidth, yPos - 1, barHeight + 2, frameColor); - for (int i = 1; i < numDividers; i++) - FastDrawVertLine(out, xPos - 1 + (barWidth * i / numDividers), yPos - dividerHeight + 3, barHeight, 245); - - FillRect(out, xPos, yPos + (space ? 1 : 0), visibleBar, barHeight - (space ? 2 : 0), barColor); -} bool HasRoomForGold() { diff --git a/Source/qol.h b/Source/qol.h index c10eb528d..64736bd42 100644 --- a/Source/qol.h +++ b/Source/qol.h @@ -12,7 +12,6 @@ namespace devilution { void FreeQol(); void InitQol(); void DrawMonsterHealthBar(CelOutputBuffer out); -void DrawXPBar(CelOutputBuffer out); void AutoGoldPickup(int pnum); } // namespace devilution diff --git a/Source/qol/common.cpp b/Source/qol/common.cpp new file mode 100644 index 000000000..62e35cf39 --- /dev/null +++ b/Source/qol/common.cpp @@ -0,0 +1,27 @@ +/** +* @file common.h +* +* Common functions for QoL features +*/ + +#include "common.h" +#include "engine.h" + +namespace devilution { + +void FastDrawHorizLine(const CelOutputBuffer &out, int x, int y, int width, BYTE col) +{ + memset(out.at(x, y), col, width); +} + +char *PrintWithSeparator(char *out, long long n) +{ + if (n < 1000) { + return out + sprintf(out, "%lld", n); + } + + char *append = PrintWithSeparator(out, n / 1000); + return append + sprintf(append, ",%03lld", n % 1000); +} + +} // namespace devilution diff --git a/Source/qol/common.h b/Source/qol/common.h new file mode 100644 index 000000000..4e4dde4d2 --- /dev/null +++ b/Source/qol/common.h @@ -0,0 +1,23 @@ +/** +* @file common.h +* +* Common functions for QoL features +*/ +#pragma once + +#include "SDL_stdinc.h" // for Uint8 + +namespace devilution { + +struct CelOutputBuffer; + +void FastDrawHorizLine(const CelOutputBuffer &out, int x, int y, int width, Uint8 col); +/** + * @brief Prints integer into buffer, using ',' as thousands separator. + * @param out Destination buffer + * @param n Number to print + * @return Address of first character after printed number +*/ +char *PrintWithSeparator(char *out, long long n); + +} // namespace devilution diff --git a/Source/qol/xpbar.cpp b/Source/qol/xpbar.cpp new file mode 100644 index 000000000..20b8f237c --- /dev/null +++ b/Source/qol/xpbar.cpp @@ -0,0 +1,154 @@ +/** +* @file xpbar.cpp +* +* Adds XP bar QoL feature +*/ + +#include "common.h" +#include "control.h" +#include "DiabloUI/art_draw.h" +#include "options.h" + +#include + +namespace devilution { + +namespace { + +constexpr int BAR_WIDTH = 307; +constexpr int BAR_HEIGHT = 5; + +using ColorGradient = std::array; +constexpr ColorGradient GOLD_GRADIENT = { 0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8, 0xC7, 0xC6, 0xC5, 0xC4 }; +constexpr ColorGradient SILVER_GRADIENT = { 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3 }; + +constexpr int BACK_WIDTH = 313; +constexpr int BACK_HEIGHT = 9; + +Art xpbarArt; + +void DrawBar(const CelOutputBuffer &out, int x, int y, int width, const ColorGradient &gradient) +{ + FastDrawHorizLine(out, x, y + 1, width, gradient[gradient.size() * 3 / 4 - 1]); + FastDrawHorizLine(out, x, y + 2, width, gradient[gradient.size() - 1]); + FastDrawHorizLine(out, x, y + 3, width, gradient[gradient.size() / 2 - 1]); +} + +void DrawEndCap(const CelOutputBuffer &out, int x, int y, int idx, const ColorGradient &gradient) +{ + SetPixel(out, x, y + 1, gradient[idx * 3 / 4]); + SetPixel(out, x, y + 2, gradient[idx]); + SetPixel(out, x, y + 3, gradient[idx / 2]); +} + +} // namespace + +void InitXPBar() +{ + if (sgOptions.Gameplay.bExperienceBar) { + LoadMaskedArt("data\\xpbar.pcx", &xpbarArt, 1, 1); + + if (xpbarArt.surface == nullptr) { + app_fatal("Failed to load UI resources. Is devilutionx.mpq accessible and up to date?"); + } + } +} + +void FreeXPBar() +{ + xpbarArt.Unload(); +} + +void DrawXPBar(const CelOutputBuffer &out) +{ + if (!sgOptions.Gameplay.bExperienceBar) + return; + + const PlayerStruct &player = plr[myplr]; + + const int backX = PANEL_LEFT + PANEL_WIDTH / 2 - 155; + const int backY = PANEL_TOP + PANEL_HEIGHT - 11; + + const int xPos = backX + 3; + const int yPos = backY + 2; + + DrawArt(out, backX, backY, &xpbarArt); + + const int charLevel = player._pLevel; + + if (charLevel == MAXCHARLEVEL - 1) { + // Draw a nice golden bar for max level characters. + DrawBar(out, xPos, yPos, BAR_WIDTH, GOLD_GRADIENT); + + return; + } + + const int prevXp = ExpLvlsTbl[charLevel - 1]; + if (player._pExperience < prevXp) + return; + + Uint64 prevXpDelta_1 = player._pExperience - prevXp; + Uint64 prevXpDelta = ExpLvlsTbl[charLevel] - prevXp; + Uint64 fullBar = BAR_WIDTH * prevXpDelta_1 / prevXpDelta; + + // Figure out how much to fill the last pixel of the XP bar, to make it gradually appear with gained XP + Uint64 onePx = prevXpDelta / BAR_WIDTH; + Uint64 lastFullPx = fullBar * prevXpDelta / BAR_WIDTH; + + const Uint64 fade = (prevXpDelta_1 - lastFullPx) * (SILVER_GRADIENT.size() - 1) / onePx; + + // Draw beginning of bar full brightness + DrawBar(out, xPos, yPos, fullBar, SILVER_GRADIENT); + + // End pixels appear gradually + DrawEndCap(out, xPos + fullBar, yPos, fade, SILVER_GRADIENT); +} + +bool CheckXPBarInfo() +{ + if (!sgOptions.Gameplay.bExperienceBar) + return false; + + const int backX = PANEL_LEFT + PANEL_WIDTH / 2 - 155; + const int backY = PANEL_TOP + PANEL_HEIGHT - 11; + + if (MouseX < backX || MouseX >= backX + BACK_WIDTH || MouseY < backY || MouseY >= backY + BACK_HEIGHT) + return false; + + const PlayerStruct &player = plr[myplr]; + + const int charLevel = player._pLevel; + + sprintf(tempstr, "Level %d", charLevel); + AddPanelString(tempstr, true); + + if (charLevel == MAXCHARLEVEL - 1) { + // Show a maximum level indicator for max level players. + infoclr = COL_GOLD; + + sprintf(tempstr, "Experience: "); + PrintWithSeparator(tempstr + SDL_arraysize("Experience: ") - 1, ExpLvlsTbl[charLevel - 1]); + AddPanelString(tempstr, true); + + AddPanelString("Maximum Level", true); + + return true; + } + + infoclr = COL_WHITE; + + sprintf(tempstr, "Experience: "); + PrintWithSeparator(tempstr + SDL_arraysize("Experience: ") - 1, player._pExperience); + AddPanelString(tempstr, true); + + sprintf(tempstr, "Next Level: "); + PrintWithSeparator(tempstr + SDL_arraysize("Next Level: ") - 1, ExpLvlsTbl[charLevel]); + AddPanelString(tempstr, true); + + sprintf(PrintWithSeparator(tempstr, ExpLvlsTbl[charLevel] - player._pExperience), " to Level %d", charLevel + 1); + AddPanelString(tempstr, true); + + return true; +} + +} // namespace devilution diff --git a/Source/qol/xpbar.h b/Source/qol/xpbar.h new file mode 100644 index 000000000..56e45d75e --- /dev/null +++ b/Source/qol/xpbar.h @@ -0,0 +1,18 @@ +/** +* @file xpbar.h +* +* Adds XP bar QoL feature +*/ +#pragma once + +namespace devilution { + +struct CelOutputBuffer; + +void InitXPBar(); +void FreeXPBar(); + +void DrawXPBar(const CelOutputBuffer &out); +bool CheckXPBarInfo(); + +} // namespace devilution diff --git a/Source/scrollrt.cpp b/Source/scrollrt.cpp index c82ca66e1..76fe8275d 100644 --- a/Source/scrollrt.cpp +++ b/Source/scrollrt.cpp @@ -24,6 +24,7 @@ #include "nthread.h" #include "plrmsg.h" #include "qol.h" +#include "qol/xpbar.h" #include "render.h" #include "stores.h" #include "towners.h"