mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-12-22 16:18:50 -05:00
[Feature] In-game gameplay stats timer (#2910)
* Implement in-game gameplay stats timer * Change timer to render on top of everything
This commit is contained in:
parent
e8eaac4d77
commit
b25e4d4f26
@ -1089,6 +1089,7 @@ void func_80088AA0(s16 seconds);
|
||||
void func_80088AF0(PlayState* play);
|
||||
void func_80088B34(s16 arg0);
|
||||
void Interface_Draw(PlayState* play);
|
||||
void Interface_DrawTotalGameplayTimer(PlayState* play);
|
||||
void Interface_Update(PlayState* play);
|
||||
Path* Path_GetByIndex(PlayState* play, s16 index, s16 max);
|
||||
f32 Path_OrientAndGetDistSq(Actor* actor, Path* path, s16 waypoint, s16* yaw);
|
||||
|
@ -321,7 +321,7 @@ static std::map<std::string, CosmeticOption> cosmeticOptions = {
|
||||
static const char* MarginCvarList[] {
|
||||
"gHearts", "gHeartsCount", "gMagicBar", "gVSOA", "gBBtn", "gABtn", "gStartBtn",
|
||||
"gCBtnU", "gCBtnD", "gCBtnL", "gCBtnR", "gDPad", "gMinimap",
|
||||
"gSKC", "gRC", "gCarrots", "gTimers", "gAS", "gTCM", "gTCB"
|
||||
"gSKC", "gRC", "gCarrots", "gTimers", "gAS", "gTCM", "gTCB", "gIGT"
|
||||
};
|
||||
static const char* MarginCvarNonAnchor[]{ "gCarrots", "gTimers", "gAS", "gTCM","gTCB" };
|
||||
|
||||
@ -1406,6 +1406,19 @@ void Draw_Placements(){
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::CollapsingHeader("In-game Gameplay Timer position")) {
|
||||
if (ImGui::BeginTable("tablegameplaytimer", 1, FlagsTable)) {
|
||||
ImGui::TableSetupColumn("In-game Gameplay Timer settings", FlagsCell, TablesCellsWidth);
|
||||
Table_InitHeader(false);
|
||||
DrawUseMarginsSlider("In-game Gameplay Timer", "gIGT");
|
||||
DrawPositionsRadioBoxes("gIGT");
|
||||
DrawPositionSlider("gIGT", 0, ImGui::GetWindowViewport()->Size.y / 2, -50,
|
||||
ImGui::GetWindowViewport()->Size.x / 2 + 10);
|
||||
DrawScaleSlider("gIGT", 1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSillyTab() {
|
||||
|
@ -276,6 +276,14 @@ std::string formatHexOnlyGameplayStat(uint32_t value) {
|
||||
return fmt::format("{:#x}", value, value);
|
||||
}
|
||||
|
||||
extern "C" char* GameplayStats_GetCurrentTime() {
|
||||
std::string timeString = formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME).c_str();
|
||||
const int stringLength = timeString.length();
|
||||
char* timeChar = new char[stringLength + 1];
|
||||
strcpy(timeChar, timeString.c_str());
|
||||
return timeChar;
|
||||
}
|
||||
|
||||
void LoadStatsVersion1() {
|
||||
std::string buildVersion;
|
||||
SaveManager::Instance->LoadData("buildVersion", buildVersion);
|
||||
@ -598,18 +606,20 @@ void DrawGameplayStatsBreakdownTab() {
|
||||
}
|
||||
|
||||
void DrawGameplayStatsOptionsTab() {
|
||||
UIWidgets::PaddedEnhancementCheckbox("Show latest timestamps on top", "gGameplayStats.TimestampsReverse");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Room Breakdown", "gGameplayStats.RoomBreakdown");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Show in-game total timer", "gGameplayStats.ShowIngameTimer", true, false);
|
||||
UIWidgets::InsertHelpHoverText("Keep track of the timer as an in-game HUD element. The position of the timer can be changed in the Cosmetics Editor.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Show latest timestamps on top", "gGameplayStats.TimestampsReverse", true, false);
|
||||
UIWidgets::PaddedEnhancementCheckbox("Room Breakdown", "gGameplayStats.RoomBreakdown", true, false);
|
||||
ImGui::SameLine();
|
||||
UIWidgets::InsertHelpHoverText("Allows a more in-depth perspective of time spent in a certain map.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("RTA Timing on new files", "gGameplayStats.RTATiming");
|
||||
UIWidgets::PaddedEnhancementCheckbox("RTA Timing on new files", "gGameplayStats.RTATiming", true, false);
|
||||
ImGui::SameLine();
|
||||
UIWidgets::InsertHelpHoverText(
|
||||
"Timestamps are relative to starting timestamp rather than in game time, usually necessary for races/speedruns.\n\n"
|
||||
"Starting timestamp is on first non-c-up input after intro cutscene.\n\n"
|
||||
"NOTE: THIS NEEDS TO BE SET BEFORE CREATING A FILE TO TAKE EFFECT"
|
||||
);
|
||||
UIWidgets::PaddedEnhancementCheckbox("Show additional detail timers", "gGameplayStats.ShowAdditionalTimers");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Show additional detail timers", "gGameplayStats.ShowAdditionalTimers", true, false);
|
||||
UIWidgets::PaddedEnhancementCheckbox("Show Debug Info", "gGameplayStats.ShowDebugInfo");
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
gSaveContext.sohStats.sceneTimer)
|
||||
|
||||
void InitStatTracker();
|
||||
char* GameplayStats_GetCurrentTime();
|
||||
|
||||
typedef enum {
|
||||
// 0x00 to 0x9B (0 to 155) used for getting items,
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
|
||||
#include "libultraship/bridge.h"
|
||||
#include "soh/Enhancements/gameplaystats.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h>
|
||||
@ -5979,6 +5980,107 @@ void Interface_Draw(PlayState* play) {
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
void Interface_DrawTotalGameplayTimer(PlayState* play) {
|
||||
// Draw timer based on the Gameplay Stats total time.
|
||||
|
||||
if (CVarGetInteger("gGameplayStats.ShowIngameTimer", 0) && gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2) {
|
||||
|
||||
s32 X_Margins_Timer = 0;
|
||||
if (CVarGetInteger("gIGTUseMargins", 0) != 0) {
|
||||
if (CVarGetInteger("gIGTPosType", 0) == 0) {
|
||||
X_Margins_Timer = Left_HUD_Margin;
|
||||
};
|
||||
}
|
||||
s32 rectLeftOri = OTRGetRectDimensionFromLeftEdge(24 + X_Margins_Timer);
|
||||
s32 rectTopOri = 73;
|
||||
if (CVarGetInteger("gIGTPosType", 0) != 0) {
|
||||
rectTopOri = (CVarGetInteger("gIGTPosY", 0));
|
||||
if (CVarGetInteger("gIGTPosType", 0) == 1) { // Anchor Left
|
||||
if (CVarGetInteger("gIGTUseMargins", 0) != 0) {
|
||||
X_Margins_Timer = Left_HUD_Margin;
|
||||
};
|
||||
rectLeftOri = OTRGetRectDimensionFromLeftEdge(CVarGetInteger("gIGTPosX", 0) + X_Margins_Timer);
|
||||
} else if (CVarGetInteger("gIGTPosType", 0) == 2) { // Anchor Right
|
||||
if (CVarGetInteger("gIGTUseMargins", 0) != 0) {
|
||||
X_Margins_Timer = Right_HUD_Margin;
|
||||
};
|
||||
rectLeftOri = OTRGetRectDimensionFromRightEdge(CVarGetInteger("gIGTPosX", 0) + X_Margins_Timer);
|
||||
} else if (CVarGetInteger("gIGTPosType", 0) == 3) { // Anchor None
|
||||
rectLeftOri = CVarGetInteger("gIGTPosX", 0) + 204 + X_Margins_Timer;
|
||||
} else if (CVarGetInteger("gIGTPosType", 0) == 4) { // Hidden
|
||||
rectLeftOri = -9999;
|
||||
}
|
||||
}
|
||||
|
||||
s32 rectLeft;
|
||||
s32 rectTop;
|
||||
s32 rectWidth = 8;
|
||||
s32 rectHeightOri = 16;
|
||||
s32 rectHeight;
|
||||
|
||||
OPEN_DISPS(play->state.gfxCtx);
|
||||
|
||||
gDPSetCombineLERP(OVERLAY_DISP++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0,
|
||||
PRIMITIVE, 0);
|
||||
|
||||
gDPSetOtherMode(OVERLAY_DISP++,
|
||||
G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_IA16 | G_TL_TILE |
|
||||
G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE,
|
||||
G_AC_NONE | G_ZS_PRIM | G_RM_XLU_SURF | G_RM_XLU_SURF2);
|
||||
|
||||
char* totalTimeText = GameplayStats_GetCurrentTime();
|
||||
char* textPointer = &totalTimeText[0];
|
||||
uint8_t textLength = strlen(textPointer);
|
||||
uint16_t textureIndex = 0;
|
||||
|
||||
for (uint16_t i = 0; i < textLength; i++) {
|
||||
if (totalTimeText[i] == ':' || totalTimeText[i] == '.') {
|
||||
textureIndex = 10;
|
||||
} else {
|
||||
textureIndex = totalTimeText[i] - 48;
|
||||
}
|
||||
|
||||
rectLeft = rectLeftOri + (i * 8);
|
||||
rectTop = rectTopOri;
|
||||
rectHeight = rectHeightOri;
|
||||
|
||||
// Load correct digit (or : symbol)
|
||||
gDPLoadTextureBlock(OVERLAY_DISP++, ((u8*)digitTextures[textureIndex]), G_IM_FMT_I, G_IM_SIZ_8b, rectWidth,
|
||||
rectHeight, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK,
|
||||
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
|
||||
|
||||
// Create dot image from the colon image.
|
||||
if (totalTimeText[i] == '.') {
|
||||
rectHeight = rectHeight / 2;
|
||||
rectTop += 5;
|
||||
rectLeft -= 1;
|
||||
}
|
||||
|
||||
// Draw text shadow
|
||||
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 0, 0, 0, 255);
|
||||
gDPSetEnvColor(OVERLAY_DISP++, 255, 255, 255, 255);
|
||||
gSPWideTextureRectangle(OVERLAY_DISP++, rectLeft << 2, rectTop << 2, (rectLeft + rectWidth) << 2,
|
||||
(rectTop + rectHeight) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
|
||||
|
||||
// Draw regular text. Change color based on if the timer is paused, running or the game is completed.
|
||||
if (gSaveContext.sohStats.gameComplete) {
|
||||
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 120, 255, 0, 255);
|
||||
} else {
|
||||
gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, 255);
|
||||
}
|
||||
|
||||
// Offset text so underlaying shadow is to the bottom right of the text.
|
||||
rectLeft -= 1;
|
||||
rectTop -= 1;
|
||||
|
||||
gSPWideTextureRectangle(OVERLAY_DISP++, rectLeft << 2, rectTop << 2, (rectLeft + rectWidth) << 2,
|
||||
(rectTop + rectHeight) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
|
||||
}
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface_Update(PlayState* play) {
|
||||
static u8 D_80125B60 = 0;
|
||||
static s16 sPrevTimeIncrement = 0;
|
||||
|
@ -1714,6 +1714,8 @@ void Play_Draw(PlayState* play) {
|
||||
}
|
||||
|
||||
CLOSE_DISPS(gfxCtx);
|
||||
|
||||
Interface_DrawTotalGameplayTimer(play);
|
||||
}
|
||||
|
||||
time_t Play_GetRealTime() {
|
||||
|
Loading…
Reference in New Issue
Block a user