From 8571bcbf07cb4733cba3e40fc88717e7d32784ae Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Mon, 28 Aug 2023 17:38:10 -0400 Subject: [PATCH] Groups UI: Add red glow tint depending on group damage / units lost --- data/base/images/intfac.img | 1 + .../images/intfac/image_but_inner_glow.png | Bin 0 -> 2165 bytes src/hci.cpp | 27 +++++-- src/hci/groups.cpp | 73 +++++++++++++++++- src/hci/groups.h | 1 + src/intfac.h | 1 + 6 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 data/base/images/intfac/image_but_inner_glow.png diff --git a/data/base/images/intfac.img b/data/base/images/intfac.img index a72978822e0..7186f80cd20 100644 --- a/data/base/images/intfac.img +++ b/data/base/images/intfac.img @@ -446,3 +446,4 @@ 0,0,image_volume_mute.png 0,0,image_but_empty_up.png 0,0,image_but_empty_down.png +0,0,image_but_inner_glow.png diff --git a/data/base/images/intfac/image_but_inner_glow.png b/data/base/images/intfac/image_but_inner_glow.png new file mode 100644 index 0000000000000000000000000000000000000000..1d833684cc94c9f3898eb055231094b95bbee19c GIT binary patch literal 2165 zcmV-*2#WWKP)RA}DimOHF1Qy9nR{n)e5QBjI0JQG(!LqRDjDoQF5G$bS* z*CQ?>Q4k?SLnTpZ=`@w25a;JZIu*`+VB|p5DJ~;#CuGn0U*?+a^9R@u7)NY_HF3?`eh$cBVh< zjN5C%Fk#sV*a5x$wo}3N*Imt=jfsVcLmLP7ei3)~eu=yl-mUHZ0QaT6U$oB)`@FL2 zf1>UJeGic9^4u(~8+yVpVNu{)zz*oCo306Fv%)QR0%Rc|+<fi*80fl=K&NZ4g_ls_K$5C~O10xUKT!2TKy7uGJd48M?k-H*aKcG1Y$?m^8++Hh)~;501R2Fy8_e9PrAG|a?>K7%Hmd_h{A=1{t(Wyc6dS|=qc~wizB?|X z9EBDH(h;M8Kc+B;>4oiHoIv(_i#in3hM`xL~a4I_~22D z!-Vo2h%H^+PzDLYFmyvt&jbG5OZ}>JCr;7@h?t@djA3(3b0T}pyeXT9YrbDBZvuPyiG7* zj|%_2#^Lq6hfpk(V=eO`u_p$|2t)_? z&DxwP6e70PkI+ODX`x807DKs68j*-lh71GGWmI+mV*r@ICLU2DA&xV~V($^yjw#Gx zl)XRz#K?=q#>^Q(&ekE**>%?Dv*-NA0xXmsp~sn2+0CCYkIC+3;wc=9(vb(esv8UQ zM{3~ghEOzwvb13$1z(#Zi%6 z3jjJmpHPINo01de*)~W72-Wu4gpP2(6WkTFemqDhdy?D$&PZfW43gY)CTBhtk`e`+ z;5oy9DI&D@#506iEI_W$ezB+;pHM57`LsqV?#o1!P%Z766ew5-Ypzf%%(~}HhEuCE zClz%QPu&&vNRG8wik0?#DnrI_NdhONqKmSca^ z2`=;eF7TXUpiG+OHaEv`x%|$A*i_u2DyE*kJaSXau)hLu*E84!I7Nd3jSFd-iCTrI zO`r-cgWXb5ITuw)UWr*8=)yC1Dl_G~02h|20!>S4s4C`S-OMvY>QOcqQc{m?>8es3 zl}oKc@-wU@KEQ!}S;8K<2Y4Zhl-QFCDIBDbqe91|P%KBUYzM&=-p%CQ4B_?#y8x#) z(E*r4^&IyKKvRG$J<4m8qC$zDrQ{Ss4nIUQJ4Y__`S$Gu90;QYhNy(WT#C++%V!Q- zi4vtaXC^Ky0c?(3sydUsbD2H36yU^engd*En^w|*d9-3F!K^LOJ?F7Pe>K9{pL_YAv- zb>E%}Yx}ZZNv;E^HQjo2BH(l1{}ilNweNjwi|vEmeW*M4xPa?>Hh&JHDh#W&e050b zT-Gab+Me&+PT0m448ZpgrL64(;GW0s6>?_+mPAlF_SX9Q z=zkgiqvG}RFTVv}e{=pHz>hq9UwG>+H-;x%rHLy{TxH@06StbU!^GVt?lp10i3dzP zWa3d1kDGYP#B(N|H}Rs0GbUa^yk^&?c-h2DCQh4p#>A5*o-py4t@)tsagT|+Ox$VW r7CXz8CN4LT?Hc~(Q`d$Q#tG|RR*Zb8m|LOM00000NkvXXu0mjfdXx>| literal 0 HcmV?d00001 diff --git a/src/hci.cpp b/src/hci.cpp index a96a970eeef..83dc731c3da 100644 --- a/src/hci.cpp +++ b/src/hci.cpp @@ -176,6 +176,7 @@ static enum _edit_pos_mode OBJECT_MODE objMode; std::shared_ptr interfaceController = nullptr; +std::shared_ptr groupsUI = nullptr; /* The current stats list being used by the stats screen */ static BASE_STATS **ppsStatsList; @@ -965,6 +966,8 @@ void interfaceShutDown() replayOverlayScreen = nullptr; } + groupsUI = nullptr; + psWScreen = nullptr; free(apsStructStatsList); @@ -1035,10 +1038,9 @@ void intDoScreenRefresh() { if (IntGroupsRefreshPending && getGroupButtonEnabled()) { - GroupsForum* groupsForum = (GroupsForum*)widgGetFromID(psWScreen, IDOBJ_GROUP); - if (groupsForum) + if (groupsUI) { - groupsForum->updateData(); + groupsUI->updateData(); } IntGroupsRefreshPending = false; } @@ -1493,6 +1495,7 @@ INT_RETVAL intRunWidgets() addIntelScreen(); // remove the groups Menu widgDelete(psWScreen, IDOBJ_GROUP); + groupsUI.reset(); reticuleCallback(RETBUT_INTELMAP); break; @@ -1507,6 +1510,7 @@ INT_RETVAL intRunWidgets() intShowPowerBar(); // remove the groups Menu widgDelete(psWScreen, IDOBJ_GROUP); + groupsUI.reset(); intAddDesign(false); intMode = INT_DESIGN; gInputManager.contexts().pushState(); @@ -2036,23 +2040,30 @@ void intGroupsChanged(bool selectionOnly) void intGroupDamaged(UBYTE group, uint64_t additionalDamage, bool unitKilled) { - // FUTURE TODO: Could update the groups UI with group damage lastTime, severity, etc + if (getGroupButtonEnabled()) + { + groupsUI->addGroupDamageForCurrentTick(group, additionalDamage, unitKilled); + } } bool intShowGroupSelectionMenu() { if (getGroupButtonEnabled()) { - GroupsForum* groupsForum = (GroupsForum*)widgGetFromID(psWScreen, IDOBJ_GROUP); - if (!groupsForum) + GroupsForum* groupsUIFormWidg = (GroupsForum*)widgGetFromID(psWScreen, IDOBJ_GROUP); + if (!groupsUIFormWidg) { - auto newGroupsForum = GroupsForum::make(); - psWScreen->psForm->attach(newGroupsForum); + if (!groupsUI) + { + groupsUI = GroupsForum::make(); + } + psWScreen->psForm->attach(groupsUI); } } else { widgDelete(psWScreen, IDOBJ_GROUP); + groupsUI.reset(); } return true; } diff --git a/src/hci/groups.cpp b/src/hci/groups.cpp index 10a83a7b2d0..f150452133e 100644 --- a/src/hci/groups.cpp +++ b/src/hci/groups.cpp @@ -39,7 +39,15 @@ class GroupsUIController: public std::enable_shared_from_this(curr.lastAccumulatedDamage, 1); + } + } + void selectGroup(size_t groupNumber) { // select the group @@ -77,10 +97,11 @@ class GroupButton : public DynamicIntFancyButton std::shared_ptr controller; std::shared_ptr groupNumberLabel; std::shared_ptr groupCountLabel; + size_t groupNumber; + uint32_t lastUpdatedGlowAlphaTime = 0; protected: GroupButton() : DynamicIntFancyButton() { } public: - size_t groupNumber; static std::shared_ptr make(const std::shared_ptr& controller, size_t groupNumber) { class make_shared_enabler: public GroupButton {}; @@ -102,6 +123,8 @@ class GroupButton : public DynamicIntFancyButton groupCountLabel->setGeometry(OBJ_TEXTX + 40, OBJ_B1TEXTY + 20, 16, 16); groupCountLabel->setString(""); groupCountLabel->setTransparentToMouse(true); + + buttonBackgroundEmpty = true; } void clickPrimary() override @@ -122,6 +145,29 @@ class GroupButton : public DynamicIntFancyButton { return; } + + if (groupInfo->lastAccumulatedDamage > 0) + { + groupInfo->currAttackGlowAlpha = std::max(groupInfo->currAttackGlowAlpha, accumulatedDamageToTargetGlowAlpha(groupInfo->lastAccumulatedDamage, groupInfo->totalGroupMaxHealth, groupInfo->lastUnitsKilled)); + lastUpdatedGlowAlphaTime = realTime; + // reset consumed values + groupInfo->lastAccumulatedDamage = 0; + groupInfo->lastUnitsKilled = 0; + } + else if (groupInfo->currAttackGlowAlpha > 0 && (realTime - lastUpdatedGlowAlphaTime) > 100) + { + auto fadeAmount = 50 * (realTime - lastUpdatedGlowAlphaTime) / GAME_TICKS_PER_SEC; + if (fadeAmount > static_cast(groupInfo->currAttackGlowAlpha)) + { + groupInfo->currAttackGlowAlpha = 0; + } + else + { + groupInfo->currAttackGlowAlpha -= static_cast(fadeAmount); + } + lastUpdatedGlowAlphaTime = realTime; + } + if (!groupInfo->numberInGroup) { groupCountLabel->setString(""); @@ -132,6 +178,12 @@ class GroupButton : public DynamicIntFancyButton displayIMD(AtlasImage(), ImdObject::DroidTemplate(&(groupInfo->displayDroidTemplate)), xOffset, yOffset); groupCountLabel->setString(WzString::fromUtf8(astringf("%u", groupInfo->numberInGroup))); } + + if (groupInfo->currAttackGlowAlpha > 0) + { + // Based on damage, display an inner glow (animated) + iV_DrawImageTint(IntImages, IMAGE_BUT_INNER_GLOW, xOffset + x(), yOffset + y(), pal_RGBA(170, 0, 0, groupInfo->currAttackGlowAlpha)); + } } std::string getTip() override { @@ -141,6 +193,17 @@ class GroupButton : public DynamicIntFancyButton { return false; } +private: + #define MAX_DAMAGE_GLOW_ALPHA 100 + inline uint8_t accumulatedDamageToTargetGlowAlpha(uint64_t accumulatedDamage, uint64_t totalGroupMaxHealth, uint64_t unitsKilled) + { + uint64_t damageVisualPercent = (accumulatedDamage * 100) / totalGroupMaxHealth; + if (unitsKilled > 0) + { + damageVisualPercent = 100; + } + return static_cast((std::min(damageVisualPercent, 100) * MAX_DAMAGE_GLOW_ALPHA) / 100); + } }; void GroupsForum::display(int xOffset, int yOffset) @@ -176,6 +239,7 @@ void GroupsUIController::updateData() struct AccumulatedGroupInfo { size_t numberInGroup = 0; + uint64_t totalGroupMaxHealth = 0; DROID *displayDroid = nullptr; std::map, size_t> unitcounter; size_t most_droids_of_same_type_in_group = 0; @@ -200,6 +264,7 @@ void GroupsUIController::updateData() currGroupInfo.displayDroid = psDroid; } currGroupInfo.numberInGroup++; + currGroupInfo.totalGroupMaxHealth += psDroid->originalBody; } for (size_t idx = 0; idx < calculatedGroupInfo.size(); ++idx) @@ -207,6 +272,7 @@ void GroupsUIController::updateData() const auto& calculatedInfo = calculatedGroupInfo[idx]; auto& storedGroupInfo = groupInfo[idx]; storedGroupInfo.numberInGroup = calculatedInfo.numberInGroup; + storedGroupInfo.totalGroupMaxHealth = calculatedInfo.totalGroupMaxHealth; if (calculatedInfo.numberInGroup > 0) { // generate a DROID_TEMPLATE from the displayDroid @@ -220,6 +286,11 @@ void GroupsForum::updateData() groupsUIController->updateData(); } +void GroupsForum::addGroupDamageForCurrentTick(size_t group, uint64_t additionalDamage, bool unitKilled) +{ + groupsUIController->addGroupDamageForCurrentTick(group, additionalDamage, unitKilled); +} + void GroupsForum::addTabList() { attach(groupsList = IntListTabWidget::make(TabAlignment::RightAligned)); diff --git a/src/hci/groups.h b/src/hci/groups.h index 08f514ed9af..a43ec2732dd 100644 --- a/src/hci/groups.h +++ b/src/hci/groups.h @@ -52,6 +52,7 @@ class GroupsForum: public IntFormAnimated return widget; } void updateData(); + void addGroupDamageForCurrentTick(size_t group, uint64_t additionalDamage, bool unitKilled); private: std::shared_ptr makeGroupButton(size_t groupNumber); void addTabList(); diff --git a/src/intfac.h b/src/intfac.h index 7e6cb08314d..bbd0aa1a513 100644 --- a/src/intfac.h +++ b/src/intfac.h @@ -480,6 +480,7 @@ enum INTFAC_TYPE IMAGE_INTFAC_VOLUME_MUTE, IMAGE_BUT_EMPTY_UP, IMAGE_BUT_EMPTY_DOWN, + IMAGE_BUT_INNER_GLOW }; #endif //__INCLUDED_SRC_INTFAC_H__