From 82d70a2029ed743c19ec3a8ace4f8221e0840824 Mon Sep 17 00:00:00 2001 From: Caladius Date: Tue, 3 Dec 2024 11:44:10 -0500 Subject: [PATCH] Add Timer Display Window (#4553) * Add new timer window and display options * Fix overflow spacing * Icons for Timers * Swap Labels for Icons. * Additional Timers * Navi Timer Icon * Clean up unused Defines. * Code clean up and double check. Ready for Review * Update from Suggestions * Update magic numbers, correct indentations hopefully * One moooooore thing * Undo z_param change * Updates --- .../parameter_static/gMoon.rgba32.png | Bin 0 -> 6114 bytes .../parameter_static/gNavi.rgba32.png | Bin 0 -> 6275 bytes .../textures/parameter_static/gSun.rgba32.png | Bin 0 -> 6448 bytes soh/assets/soh_assets.h | 9 + .../Enhancements/TimeDisplay/TimeDisplay.cpp | 262 ++++++++++++++++++ .../Enhancements/TimeDisplay/TimeDisplay.h | 37 +++ soh/soh/SohGui.cpp | 5 + soh/soh/SohMenuBar.cpp | 32 +++ soh/src/code/z_parameter.c | 2 +- 9 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 soh/assets/custom/textures/parameter_static/gMoon.rgba32.png create mode 100644 soh/assets/custom/textures/parameter_static/gNavi.rgba32.png create mode 100644 soh/assets/custom/textures/parameter_static/gSun.rgba32.png create mode 100644 soh/soh/Enhancements/TimeDisplay/TimeDisplay.cpp create mode 100644 soh/soh/Enhancements/TimeDisplay/TimeDisplay.h diff --git a/soh/assets/custom/textures/parameter_static/gMoon.rgba32.png b/soh/assets/custom/textures/parameter_static/gMoon.rgba32.png new file mode 100644 index 0000000000000000000000000000000000000000..9c1afa577ffd13c4f63b89be8eadc2428d00c19f GIT binary patch literal 6114 zcmeHLc~}$I77t(%Sp-@XS(G$d1WJ|(2_X?sBw#26!%~6ziB6J92#|#&5Ec2!F@q&-xCDE1+6SvWU(#J>XUaTprVDU-}m~TlP{B*bAIP{&;8wV zPclj8_%1WhHP^*pFa};Mra$;JLf<;t;B57H6vkktS;hwjEB#>=RwkDUM3D$q87D)q zNUTVJ!NlIE3<}Bq#YX>GkBMU10;9BhKX}$zGz~3m^j3XY8?k+zwZ2^gE-(Fu%fBX# z>OVFl)Lc5}eQn#)AC9gaPIu5h+>sZ=Zaok`3LD-lzg?uYg^=1RUQGSvapt-zTCvUP zY-vXIBdz-}*e5qn-lE^FjQZrK>W)V?{TY^0t?ES=Rt7sR*m~RDCNZMJI9+mNd*1bx zZH6c3w?(8xTPjpP+lTj@(r&oYVUZ6lsqigGi*GkRd{k?OPVL>kx{r;v&S+Wfd(7{C zb?>p;ofY@vO71>l%@iiIOIeS!J8Neqt!{rP84@Qc{_#0)psi$N4*UE!W`2CDCDCmg z7)wKDch9ni@>ggjHF|bxnnvYqENyF8pX`aOT4~v`s8MPCZE3NEC_IBiji%)EN;2(MUl-IuK3$9yKSN0c>WHa>`r}HK3g1xjylMG5qn_pNnKI6Hq+0RY>{EtUOV*`*k1728%+8_j*2EuE z-7{xv?Sdcb#>|L|GBgZ5770~-z|gq5V2#r) zPpXKe!|7ClePVTHas8~Odl6j^f7>>* zPq$vbvomJUm?MnKDcWK2_?wQSKcyO0RMmUrgoX=?`}2wT)eS@5&#z~fB$rq;S*>u& zun$-+q1TPNC0{LhviSGKpSCqSU*9_KF$SZtQRME<@p5;6(I-H6C`!z7VV&lfe7!ti zPwAJ_7o|Bd_xi^88K3t*iwm|9f4yR^Pv{@h+2+|Mrpp=+-??*@+tPS8Bxrh&o6$3k zs2G{QGV9|3Z(Tfh?O?1`Prc&ki0hKDz=H4?4~;JmZ3%R?7APvXcV;E(Xv}FSIOF4z z724FGNW6La{MF++SBKY)^gIX}w$@sUi^}cW?X=HMJW;E^^X^X{W#0=XYXTbVyg-*^tU>!40GTIV9=0eZJ3yv^xX$x-uGS_=@-3=LQkhWXiZLr}88(o~bbL%~6K<9b6gSuY z_h~uxq}BQp^8K#YF6V=O9wP#MJDBam;7P>4L)nKlVj_Vi}wLl3t=1R{`ijjD=-Hh(IEW#l(pb3Z+L3AQ?|+(g;N$`1&LI zBMND>oQHVCAQI*Li4=U^%XnF|JW@R!K97h*B4PklfKj2>hFs>w=DdtRB@l|lGIbOX z`!%FeBzPs(Yq_Bw^>ijC0>WSNzJ`7=cQqKG*lY$<%8N$R^J2Q-(D503DNn>_s4rqngf~S2szOx6uKjoM0o{Tfyfo07ExA+L~s~O z0$msem=2H@Mk^H%s3X8^818ZeR!Zf8QfZ_M4ov}zM!s~j!G_|)N|*^N5kN{JQy37$ zfark`odMApR0^I%WsoM|rF@Yf?rmsv`(T~N7M&$hfbrwhrm;O0fJBYmjon6y)SC&5 zRc{Lh%p0460**oW>O2A0n2Q$%ON0pMAL9l4!Y-Pm7`Rk~LV+E@;z1PjL?Yo~KI8f*RxTDA?P{)$?y<_pCB2II6he- z+A&_t)|vPxJ)G5m2`vW1joCo!0-ccfvK5Z&g*KhP@fcr+zi|XW{b7*z()WX0ALM#3 z1>Ot%p}IcE^36?jxiWp%fM$1H8G_cA7C6n*Wi|1Jku zX2@6}3JgZ?6ZEZtDJ+@;jMJ4~Y>(-^dL|fSM@>DY75LB1!i(t^=wz&6G;QE1KumtL zwziH=JSIm?Vl6K(pBSgUo&+|zsio!GpMtZpvPLIIzhOmzlO1osroNplxTB-vt)pvB zO^LzO)YSZyTkTU596562ts_mvq$aSmw4BQSZuax%&rT+R+V(aEbp}_On%{i91`*;d18XiyqX`&`r3CpSx%l5{uV59|BTzU{8R~dF^ae*!D&eFUfHWUlRU=-A= zC?YBnQBf3(i3JpU0ed4B1Qb!ag?na}!Nuf0_xe0H|2#ayIp;g?_kQ1bPZ@?ZUvCc! z)6u371X&0@-TXmqg*_%l;J59Y9vFfK{+bvVjQYcIB$Zkzl|>^YG(m-ska(FCg5q!Q zm>re7*WUcyrODF4<10?6-Ttks1c#PF8d#x^C%~G6ji&thb2=ER7OmTvk7t=(Oz}DV{%dsOPW<=T$Ah_xv|=R$-GJ{ z@qE9Or$eu~PITs9ToI62GiaBu_R6S;JWul@f;qdh3j;!{T?ScEc&81%erk9n)o<3r zGpEhpH#zLmq^zwmK`E=6YG0)<`x)L&jT|MSt0$B(?MCLE`^Bg2j^(k89W(NgXQpKv zjBlkdvd7FWa~|68Q{Z8%ip@8~^^se*j+vS>sjW6s!gU>ciya9Nz3z0 zoA5(%L3mH$uc?zcwbu*n*5%5JyR35$-t_m_t=)d~Me*Bjj<(*sR(w0VE%t*8CwF(t zw(BbM^2mLu`<87j*<6-4YM>YyymGmn!LZ!r(vUMD-&9*%KqW<{%iX;d^MhpeMuX(z zVmEVNeD%vp%O@XZ^1f~o@;)4|-eq@>wywOfJwL=IBX7U`q2d$HySc$huY^-OWlNlt zL5J67+ajZfoG3jwBE!e4tu`#g=Roz#+V*9V0o$5tPT0EKomOPou+&cB9hyz8n62?C z*V)0ZrvdK3P-xR*x-}$t*jp@IC%2R43 z8ug$fmlRc1T*R@-NMmyDKs}zFl#Jq6A}vcIy;g`SCkBfbSO>Jd@%I~o&P}LV(0EG8 z{5GWZ+T6nFAr1E~`0n*w9~QaERmj=%)J2Ube0wvTR*~>kkW(azgDBNTW~It{8Fodu4h}dt>0mMXlzj-ODuIiN-5t z^)1i+Ys`){KTKR0?Qgb^GBMtE`;C^tA8h9}TfPhA9pXTc!4jFPtFO@2mAJ{k{k176 z%gOWPjIpQZ1+3ck^`KQN93+L_v3^6V{7;jE?d8jYY-Um4FaFj-xN_C@hasw0;*y4k zbwzuY>>-&Xr#MV=m~_-Lt;frh67J~mvZ{PRMtNMyHn&8^fJ-gfAs{QVLv{QZsW2{?@TAB)WXzow6ELodx zwPm=^XwzEa8RW%U7HZH$G=`erD=SN7u1IfoonbD>`TTjB+t@ zM`cLIW19KX(sk?`vUI!j3F9-DnvCLP`z=~#vUl{PZ~YJ2zIl})_%Qy6M7{3!GbJgL z13lAi-wjEQi?S}*c{e}I+@#`WdzHiGV`l8eL+_KK?_3!ETaWpVGWo(%gY!vi=PIKf zjSCAKQ&y&kdi{;+$bi+3&)3@V*KR5BwTGG`T1EV@dh7asXck1h_@mX}jPLAoyx)Ge zqxLsbjnV z5Xcb}CdJF66&gXj6B*|ffHr2Pkx4iNjdCIfi+oA0N;N`aQ`uBH#XVjY%Op=XB{`}k zQh~qQ_q`OL=R}^5qACH678e&sjbl-j>IfQx&*#(VOd69(0SJmFL4m^Y6oqCSMxoZ>K+S7 zdK3Cf4^1F=KhyjXjZ&)?Bkr+?0v)GMArbfatF-E9d^!>_4T(nN0IC5|8T~?f2t~eq z9+(6XGPw%(0%G?=qB7}6vHInPjo{PKPXxI4@%BR#bH~8|B@zkTlwvKGp3u#SjKvp7 zlwz4gfHx6DEaf=RVG5naW>eS*k4fQk9at2mgIJ7kSqLKG()Fl>3JnS?#0W+O$f+{G zBjt&u^zd*dg^9pi3Y#TmQyjPm0w_2f29qu2aK(H*3Lmu$>`FLVKP!w%0;t02bQZ#A zaVUH#pHE?Pcnk_0E@4r`bf$#EWs12>4vbSt#DedYYB>y+QznNa5SmI6fe&DU3!Ht0 zPGlxkmpE?mjfPPvZ~$jOrjRJ(G#|l%GC2}}!kC^69*fCjvAIkpht6X#xF115h*|^o zBF4&~Q(3wZY+(doIzU<&+o^y6_W-jIxT+BtRjLD(%4jDtmI4X$>>Cz=10{h`*bPPz zKuTw_1q_CO$p~cd1q_~m&ZN*e0=gbvDUnGN{u>%QJ|suoqI=3TAbtXF(w(UQBu3ZM zb)#kYVIq<6V0{4|fP>iKSd7B4PDs*C?fE9IQs1BY=)TE3iRvtw{F0OEsxKK5jmOtpkvZ z!eCJJBqP&$CriU_3}Uv9v_I+Lhy(Pl7~rR~fvXGLgtWe^uvaha()k-p?>hXA5dig< zAfKi07rDO3^;rsh7Wm8V`Xbk7Dezg~FT3miCYR~Qk10d}{sM{vpGxXP=sx(&G79(d zaD#fVpRLDs{sb(8Ri1M+5M(wCdkn7LOMVB8#;8!_Zd`9>4GlF+JLG8x{wX*{=;j>g zFx0?mVDnq32NVFqi-CawggyUj>F)0CF~q?7Bp4q-^eLHszpJaO=fj5&;L{#NBnSuq zQR`=d+4Sw5ot=2*hQtgAlHQE^fe9i4i$y1F_!Ni^NC_X%k3@`p>P%#W6BrsA_9;hX zLOAG?VUaOA_81!*<34>E0H8hz9+)r@HD<)xCMG6*SiC_1df9c;*hD0+tGniQ;|(Hm z-zeeSX8;X@RZp-~`xR)TZogo7;?eiP+c=rJqNk#wqMtL-AxJPVLDHwepVK?neUQu+)S0kIP?jDhA@KWNVy*S1Wg8QlU~=W0oX+Y3EjQjie17M{~KltvSk1O literal 0 HcmV?d00001 diff --git a/soh/assets/custom/textures/parameter_static/gSun.rgba32.png b/soh/assets/custom/textures/parameter_static/gSun.rgba32.png new file mode 100644 index 0000000000000000000000000000000000000000..954726e0580b287195b4dc623f6d52abda68a635 GIT binary patch literal 6448 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 XfcD^C{N-TuqJjMQ{=9=T!&d$q;WOf= literal 0 HcmV?d00001 diff --git a/soh/assets/soh_assets.h b/soh/assets/soh_assets.h index c0acacf21..568a87963 100644 --- a/soh/assets/soh_assets.h +++ b/soh/assets/soh_assets.h @@ -106,6 +106,15 @@ static const ALIGN_ASSET(2) char gSplitEntranceTex[] = dgSplitEntrance; #define dgBossSoul "__OTR__textures/parameter_static/gBossSoul" static const ALIGN_ASSET(2) char gBossSoulTex[] = dgBossSoul; +#define dgMoonIcon "__OTR__textures/parameter_static/gMoon" +static const ALIGN_ASSET(2) char gMoonIconTex[] = dgMoonIcon; + +#define dgSunIcon "__OTR__textures/parameter_static/gSun" +static const ALIGN_ASSET(2) char gSunIconTex[] = dgSunIcon; + +#define dgNaviIcon "__OTR__textures/parameter_static/gNavi" +static const ALIGN_ASSET(2) char gNaviIconTex[] = dgNaviIcon; + #define dgFileSelMQButtonTex "__OTR__textures/title_static/gFileSelMQButtonTex" static const ALIGN_ASSET(2) char gFileSelMQButtonTex[] = dgFileSelMQButtonTex; diff --git a/soh/soh/Enhancements/TimeDisplay/TimeDisplay.cpp b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.cpp new file mode 100644 index 000000000..cb9dfbb46 --- /dev/null +++ b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.cpp @@ -0,0 +1,262 @@ +#include "TimeDisplay.h" +#include "soh/Enhancements/gameplaystats.h" +#include + +#include "assets/textures/parameter_static/parameter_static.h" +#include "assets/soh_assets.h" +#include "soh/ImGuiUtils.h" + +extern "C" { +#include "macros.h" +#include "functions.h" +#include "variables.h" +extern PlayState* gPlayState; +uint64_t GetUnixTimestamp(); +} + +float fontScale = 1.0f; +std::string timeDisplayTime = ""; +ImTextureID textureDisplay = 0; +ImVec4 windowBG = ImVec4(0, 0, 0, 0.5f); +ImVec4 textColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + +// ImVec4 Colors +#define COLOR_WHITE ImVec4(1.0f, 1.0f, 1.0f, 1.0f) +#define COLOR_LIGHT_RED ImVec4(1.0f, 0.05f, 0, 1.0f) +#define COLOR_LIGHT_BLUE ImVec4(0, 0.88f, 1.0f, 1.0f) +#define COLOR_LIGHT_GREEN ImVec4(0.52f, 1.0f, 0.23f, 1.0f) +#define COLOR_GREY ImVec4(0.78f, 0.78f, 0.78f, 1.0f) + +const static std::vector> digitList = { + { "DIGIT_0_TEXTURE", gCounterDigit0Tex }, { "DIGIT_1_TEXTURE", gCounterDigit1Tex }, + { "DIGIT_2_TEXTURE", gCounterDigit2Tex }, { "DIGIT_3_TEXTURE", gCounterDigit3Tex }, + { "DIGIT_4_TEXTURE", gCounterDigit4Tex }, { "DIGIT_5_TEXTURE", gCounterDigit5Tex }, + { "DIGIT_6_TEXTURE", gCounterDigit6Tex }, { "DIGIT_7_TEXTURE", gCounterDigit7Tex }, + { "DIGIT_8_TEXTURE", gCounterDigit8Tex }, { "DIGIT_9_TEXTURE", gCounterDigit9Tex }, + { "COLON_TEXTURE", gCounterColonTex }, +}; + +const std::vector timeDisplayList = { + { DISPLAY_IN_GAME_TIMER, "Display Gameplay Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.InGameTimer") }, + { DISPLAY_TIME_OF_DAY, "Display Time of Day", CVAR_ENHANCEMENT("TimeDisplay.Timers.TimeofDay") }, + { DISPLAY_CONDITIONAL_TIMER, "Display Conditional Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.HotWater") }, + { DISPLAY_NAVI_TIMER, "Display Navi Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.NaviTimer") } +}; + +static std::vector activeTimers; + +std::string convertDayTime(uint32_t dayTime) { + uint32_t totalSeconds = 24 * 60 * 60; + uint32_t ss = static_cast(static_cast(dayTime) * (totalSeconds - 1) / 65535); + uint32_t hh = ss / 3600; + uint32_t mm = (ss % 3600) / 60; + return fmt::format("{:0>2}:{:0>2}", hh, mm); +} + +std::string convertNaviTime(uint32_t value) { + uint32_t totalSeconds = value * 0.05; + uint32_t ss = totalSeconds % 60; + uint32_t mm = totalSeconds / 60; + return fmt::format("{:0>2}:{:0>2}", mm, ss); +} + +std::string formatHotWaterDisplay(uint32_t value) { + uint32_t ss = value % 60; + uint32_t mm = value / 60; + return fmt::format("{:0>2}:{:0>2}", mm, ss); +} + +std::string formatTimeDisplay(uint32_t value) { + uint32_t sec = value / 10; + uint32_t hh = sec / 3600; + uint32_t mm = (sec - hh * 3600) / 60; + uint32_t ss = sec - hh * 3600 - mm * 60; + uint32_t ds = value % 10; + return fmt::format("{}:{:0>2}:{:0>2}.{}", hh, mm, ss, ds); +} + +static void TimeDisplayGetTimer(uint32_t timeID) { + timeDisplayTime = ""; + textureDisplay = 0; + textColor = COLOR_WHITE; + + Player* player = GET_PLAYER(gPlayState); + uint32_t timer1 = gSaveContext.timer1Value; + + switch (timeID) { + case DISPLAY_IN_GAME_TIMER: + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("GAMEPLAY_TIMER"); + timeDisplayTime = formatTimeDisplay(GAMEPLAYSTAT_TOTAL_TIME).c_str(); + break; + case DISPLAY_TIME_OF_DAY: + if (gSaveContext.dayTime >= DAY_BEGINS && gSaveContext.dayTime < NIGHT_BEGINS) { + textureDisplay = + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("DAY_TIME_TIMER"); + } else { + textureDisplay = + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("NIGHT_TIME_TIMER"); + } + timeDisplayTime = convertDayTime(gSaveContext.dayTime).c_str(); + break; + case DISPLAY_CONDITIONAL_TIMER: + if (gSaveContext.timer1State > 0) { + timeDisplayTime = formatHotWaterDisplay(gSaveContext.timer1Value).c_str(); + textColor = + gSaveContext.timer1State <= 4 + ? (gPlayState->roomCtx.curRoom.behaviorType2 == ROOM_BEHAVIOR_TYPE2_3 ? COLOR_LIGHT_RED + : COLOR_LIGHT_BLUE) + : COLOR_WHITE; + if (gSaveContext.timer1State <= 4) { + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + gPlayState->roomCtx.curRoom.behaviorType2 == ROOM_BEHAVIOR_TYPE2_3 + ? itemMapping[ITEM_TUNIC_GORON].name + : itemMapping[ITEM_TUNIC_ZORA].name); + } + if (gSaveContext.timer1State >= 6) { + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + itemMapping[ITEM_SWORD_MASTER].name); + } + } else { + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + itemMapping[ITEM_TUNIC_KOKIRI].name); + timeDisplayTime = "-:--"; + } + break; + case DISPLAY_NAVI_TIMER: + if (gSaveContext.naviTimer <= NAVI_PREPARE) { + timeDisplayTime = convertNaviTime(NAVI_PREPARE - gSaveContext.naviTimer).c_str(); + } else if (gSaveContext.naviTimer <= NAVI_ACTIVE) { + timeDisplayTime = convertNaviTime(NAVI_ACTIVE - gSaveContext.naviTimer).c_str(); + textColor = COLOR_LIGHT_GREEN; + } else { + timeDisplayTime = convertNaviTime(NAVI_COOLDOWN - gSaveContext.naviTimer).c_str(); + textColor = COLOR_GREY; + } + textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("NAVI_TIMER"); + break; + default: + break; + } +} + +void TimeDisplayUpdateDisplayOptions() { + activeTimers.clear(); + for (auto& timer : timeDisplayList) { + if (CVarGetInteger(timer.timeEnable, 0)) { + activeTimers.push_back(timer); + } + } + + //if (pushBack) { + // activeTimers.push_back(timeDisplayList[timeID]); + //} else { + // uint32_t index = 0; + // for (auto& check : activeTimers) { + // if (check.timeID == timeID) { + // activeTimers.erase(activeTimers.begin() + index); + // return; + // } + // index++; + // } + //} +} + +void TimeDisplayWindow::Draw() { + if (!gPlayState) { + return; + } + if (!CVarGetInteger(CVAR_WINDOW("TimeDisplayEnabled"), 0)) { + return; + } + + ImGui::PushStyleColor(ImGuiCol_WindowBg, windowBG); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); + + ImGui::Begin("TimerDisplay", nullptr, + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar); + ImGui::SetWindowFontScale(fontScale); + if (activeTimers.size() == 0) { + ImGui::Text("No Enabled Timers..."); + } else { + ImGui::BeginTable("Timer List", 2, ImGuiTableFlags_NoClip); + for (auto& timers : activeTimers) { + ImGui::PushID(timers.timeID); + TimeDisplayGetTimer(timers.timeID); + ImGui::TableNextColumn(); + ImGui::Image(textureDisplay, ImVec2(16.0f * fontScale, 16.0f * fontScale)); + ImGui::TableNextColumn(); + + if (timeDisplayTime != "-:--") { + char* textToDecode = new char[timeDisplayTime.size() + 1]; + textToDecode = std::strcpy(textToDecode, timeDisplayTime.c_str()); + size_t textLength = timeDisplayTime.length(); + uint16_t textureIndex = 0; + + for (size_t i = 0; i < textLength; i++) { + ImVec2 originalCursorPos = ImGui::GetCursorPos(); + if (textToDecode[i] == ':' || textToDecode[i] == '.') { + textureIndex = 10; + } else { + textureIndex = textToDecode[i] - '0'; + } + if (textToDecode[i] == '.') { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (8.0f * fontScale)); + ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + digitList[textureIndex].first), + ImVec2(8.0f * fontScale, 8.0f * fontScale), ImVec2(0, 0.5f), ImVec2(1, 1), + textColor, ImVec4(0, 0, 0, 0)); + } else { + ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName( + digitList[textureIndex].first), + ImVec2(8.0f * fontScale, 16.0f * fontScale), ImVec2(0, 0), ImVec2(1, 1), textColor, + ImVec4(0, 0, 0, 0)); + } + ImGui::SameLine(0, 0); + } + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::End(); + + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(1); +} + +void TimeDisplayInitSettings() { + fontScale = CVarGetFloat(CVAR_ENHANCEMENT("TimeDisplay.FontScale"), 1.0f); + if (fontScale < 1.0f) { + fontScale = 1.0f; + } + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeDisplay.ShowWindowBG"), 0)) { + windowBG = ImVec4(0, 0, 0, 0); + } else { + windowBG = ImVec4(0, 0, 0, 0.5f); + } +} + +static void TimeDisplayInitTimers() { + for (auto& update : timeDisplayList) { + if (CVarGetInteger(update.timeEnable, 0)) { + activeTimers.push_back(update); + } + } +} + +void TimeDisplayWindow::InitElement() { + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("GAMEPLAY_TIMER", gClockIconTex, ImVec4(1, 1, 1, 1)); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("DAY_TIME_TIMER", gSunIconTex, ImVec4(1, 1, 1, 1)); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("NIGHT_TIME_TIMER", gMoonIconTex, ImVec4(1, 1, 1, 1)); + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("NAVI_TIMER", gNaviIconTex, ImVec4(1, 1, 1, 1)); + + for (auto& load : digitList) { + Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(load.first.c_str(), load.second, ImVec4(1, 1, 1, 1)); + } + + TimeDisplayInitSettings(); + TimeDisplayInitTimers(); +} diff --git a/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h new file mode 100644 index 000000000..090ac2901 --- /dev/null +++ b/soh/soh/Enhancements/TimeDisplay/TimeDisplay.h @@ -0,0 +1,37 @@ +#include + +class TimeDisplayWindow : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + + void InitElement() override; + void DrawElement() override {}; + void Draw() override; + void UpdateElement() override {}; +}; + +void TimeDisplayUpdateDisplayOptions(); +void TimeDisplayInitSettings(); + +typedef enum { + DISPLAY_IN_GAME_TIMER, + DISPLAY_TIME_OF_DAY, + DISPLAY_CONDITIONAL_TIMER, + DISPLAY_NAVI_TIMER +}; + +typedef enum { + NAVI_PREPARE = 600, + NAVI_ACTIVE = 3000, + NAVI_COOLDOWN = 25800, + DAY_BEGINS = 17759, + NIGHT_BEGINS = 49155 +}; + +typedef struct { + uint32_t timeID; + std::string timeLabel; + const char* timeEnable; +} TimeObject; + +extern const std::vector timeDisplayList; \ No newline at end of file diff --git a/soh/soh/SohGui.cpp b/soh/soh/SohGui.cpp index 19b8639de..2dbf62a99 100644 --- a/soh/soh/SohGui.cpp +++ b/soh/soh/SohGui.cpp @@ -38,6 +38,7 @@ #include "Enhancements/resolution-editor/ResolutionEditor.h" #include "Enhancements/debugger/MessageViewer.h" #include "soh/Notification/Notification.h" +#include "soh/Enhancements/TimeDisplay/TimeDisplay.h" bool isBetaQuestEnabled = false; @@ -136,6 +137,7 @@ namespace SohGui { std::shared_ptr mAdvancedResolutionSettingsWindow; std::shared_ptr mModalWindow; std::shared_ptr mNotificationWindow; + std::shared_ptr mTimeDisplayWindow; void SetupGuiElements() { auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); @@ -221,6 +223,8 @@ namespace SohGui { mNotificationWindow = std::make_shared(CVAR_WINDOW("Notifications"), "Notifications Window"); gui->AddGuiWindow(mNotificationWindow); mNotificationWindow->Show(); + mTimeDisplayWindow = std::make_shared(CVAR_WINDOW("TimeDisplayEnabled"), "Additional Timers"); + gui->AddGuiWindow(mTimeDisplayWindow); } void Destroy() { @@ -256,6 +260,7 @@ namespace SohGui { mInputViewerSettings = nullptr; mTimeSplitWindow = nullptr; mPlandomizerWindow = nullptr; + mTimeDisplayWindow = nullptr; } void RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function button1callback, std::function button2callback) { diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index cd9948092..a6cbd2d81 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -44,6 +44,7 @@ #include "Enhancements/enemyrandomizer.h" #include "Enhancements/timesplits/TimeSplits.h" #include "Enhancements/randomizer/Plandomizer.h" +#include "Enhancements/TimeDisplay/TimeDisplay.h" // FA icons are kind of wonky, if they worked how I expected them to the "+ 2.0f" wouldn't be needed, but // they don't work how I expect them to so I added that because it looked good when I eyeballed it @@ -607,6 +608,7 @@ extern std::shared_ptr mAudioEditorWindow; extern std::shared_ptr mCosmeticsEditorWindow; extern std::shared_ptr mGameplayStatsWindow; extern std::shared_ptr mTimeSplitWindow; +extern std::shared_ptr mTimeDisplayWindow; void DrawEnhancementsMenu() { if (ImGui::BeginMenu("Enhancements")) @@ -1723,6 +1725,36 @@ void DrawEnhancementsMenu() { mTimeSplitWindow->ToggleVisibility(); } } + + if (mTimeDisplayWindow) { + if (ImGui::Button(GetWindowButtonText("Additional Timers", CVarGetInteger(CVAR_WINDOW("TimeDisplayEnabled"), 0)).c_str(), ImVec2(-1.0f, 0.0f))) { + mTimeDisplayWindow->ToggleVisibility(); + } + } + if (mTimeDisplayWindow->IsVisible()) { + ImGui::SeparatorText("Timer Display Options"); + + if (!gPlayState) { + ImGui::Text("Additional Timer options\n" + "available when a file is\n" + "loaded..."); + } else { + if (UIWidgets::PaddedEnhancementSliderFloat("Font Scale: %.2fx", "##FontScale", CVAR_ENHANCEMENT("TimeDisplay.FontScale"), + 1.0f, 5.0f, "", 1.0f, false, true, false, true)) { + TimeDisplayInitSettings(); + } + if (UIWidgets::PaddedEnhancementCheckbox("Hide Background", CVAR_ENHANCEMENT("TimeDisplay.ShowWindowBG"), + false, false)) { + TimeDisplayInitSettings(); + } + ImGui::Separator(); + for (auto& timer : timeDisplayList) { + if (UIWidgets::PaddedEnhancementCheckbox(timer.timeLabel.c_str(), timer.timeEnable, false, false)) { + TimeDisplayUpdateDisplayOptions(); + } + } + } + } ImGui::PopStyleVar(3); ImGui::PopStyleColor(1); diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 84c71c83b..d2c3e1a26 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -6070,7 +6070,7 @@ void Interface_Draw(PlayState* play) { svar5 = CVarGetInteger(CVAR_COSMETIC("HUD.Timers.PosX"), 0)+204+X_Margins_Timer; } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Timers.PosType"), 0) == 4) {//Hidden svar5 = -9999; - } + } } OVERLAY_DISP =