Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Hit counter #84

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions HollowKnightComponent.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#if !Info
using LiveSplit.Model;
using LiveSplit.TimeFormatters;
using LiveSplit.UI;
using LiveSplit.UI.Components;
#endif
Expand Down Expand Up @@ -52,6 +53,10 @@ public class HollowKnightComponent {
private List<string> menuingSceneNames = new List<string> { "Menu_Title", "Quit_To_Menu", "PermaDeath" };
private List<string> debugSaveStateSceneNames = new List<string> { "Room_Mender_House", "Room_Sly_Storeroom" };

private string lastExitingLevel;
private int hits = 0;
private List<int> segmentHits = new List<int>();

enum SplitterAction {
Pass,
Split,
Expand Down Expand Up @@ -85,6 +90,11 @@ public HollowKnightComponent(LiveSplitState state) {
state.OnSplit += OnSplit;
state.OnUndoSplit += OnUndoSplit;
state.OnSkipSplit += OnSkipSplit;
state.Run.Metadata.SetCustomVariable("hits", "0");
state.Run.Metadata.SetCustomVariable("segment hits", "0");
state.Run.Metadata.SetCustomVariable("pb hits", TimeFormatConstants.DASH);
state.Run.Metadata.SetCustomVariable("comparison hits", TimeFormatConstants.DASH);
state.Run.Metadata.SetCustomVariable("delta hits", TimeFormatConstants.DASH);

if (state.CurrentTimingMethod == TimingMethod.RealTime) {
var timingMessage = MessageBox.Show(
Expand Down Expand Up @@ -172,6 +182,7 @@ private void HandleSplits() {
}
}
LoadRemoval(gameState, uIState, nextScene, sceneName);
HandleHits(gameState, uIState, nextScene, sceneName);
}

store.Update();
Expand Down Expand Up @@ -212,6 +223,95 @@ private void LoadRemoval(GameState gameState, UIState uIState, string nextScene,
lastGameState = gameState;
}

private void HitsReset() {
hits = 0;
segmentHits.Clear();
Model.CurrentState.Run.Metadata.SetCustomVariable("hits", "0");
Model.CurrentState.Run.Metadata.SetCustomVariable("segment hits", "0");
}

private void HitsIndexChanged() {
while (segmentHits.Count < currentSplit + 1) {
segmentHits.Add(0);
}
Model.CurrentState.Run.Metadata.SetCustomVariable("segment hits", segmentHits[currentSplit].ToString());
if (currentSplit >= 0 && currentSplit < settings.ComparisonHits.Count) {
Model.CurrentState.Run.Metadata.SetCustomVariable("comparison hits", settings.ComparisonHits[currentSplit].ToString());
Model.CurrentState.Run.Metadata.SetCustomVariable("delta hits", DeltaString(hits - settings.ComparisonHits[currentSplit]));
} else {
Model.CurrentState.Run.Metadata.SetCustomVariable("comparison hits", TimeFormatConstants.DASH);
Model.CurrentState.Run.Metadata.SetCustomVariable("delta hits", TimeFormatConstants.DASH);
}
while (settings.ComparisonHits.Count < currentSplit) {
settings.ComparisonHits.Add(hits);
}
if (currentSplit >= 1) {
settings.ComparisonHits[currentSplit - 1] = Math.Min(settings.ComparisonHits[currentSplit - 1], hits);
if (Model.CurrentState.CurrentPhase == TimerPhase.Ended) {
Model.CurrentState.Run.Metadata.SetCustomVariable("pb hits", settings.ComparisonHits[settings.ComparisonHits.Count - 1].ToString());
}
}
}

private void HandleHits(GameState gameState, UIState _uIState, string _nextScene, string sceneName) {
// TODO: set segment hits to 0 when moving to a new segment, also reset delta hits at the same time
// TODO: also reset these when resetting the run
if (settings.HitCounter is HollowKnightSettings.HitsMethod.None) {
return;
}

if (store.RecoilFrozenToggledTrue()) {
AddHit();
}
if (store.HazardDeathToggledTrue()) {
AddHit();
}
if (store.CheckDecreasedTo(Offset.health, 0)) {
AddHit();
}

if (settings.HitCounter is HollowKnightSettings.HitsMethod.HitsDreamFalls) {
if (gameState == GameState.ENTERING_LEVEL && lastExitingLevel == sceneName && IsDream(sceneName)) {
AddHit();
}
if (gameState == GameState.EXITING_LEVEL) {
lastExitingLevel ??= sceneName;
} else {
lastExitingLevel = null;
}
}
}

private bool IsDream(string sceneName) {
return sceneName.StartsWith("Dream_")
|| (sceneName.StartsWith("GG_") && !sceneName.Contains("way") && !sceneName.Contains("Lurker"));
}

private void AddHit() {
hits += 1;
Model.CurrentState.Run.Metadata.SetCustomVariable("hits", hits.ToString());
while (segmentHits.Count < currentSplit + 1) {
segmentHits.Add(0);
}
segmentHits[currentSplit] += 1;
Model.CurrentState.Run.Metadata.SetCustomVariable("segment hits", segmentHits[currentSplit].ToString());
if (currentSplit < settings.ComparisonHits.Count) {
Model.CurrentState.Run.Metadata.SetCustomVariable("delta hits", DeltaString(hits - settings.ComparisonHits[currentSplit]));
} else {
Model.CurrentState.Run.Metadata.SetCustomVariable("delta hits", TimeFormatConstants.DASH);
}
}

private string DeltaString(int delta) {
if (delta > 0) {
return "+" + delta.ToString();
} else if (delta < 0) {
return TimeFormatConstants.MINUS + (-delta).ToString();
} else {
return delta.ToString();
}
}

private SplitterAction NotOrderedSplits(GameState gameState, UIState uIState, string nextScene, string sceneName) {

foreach (SplitName Split in settings.Splits) {
Expand Down Expand Up @@ -1929,6 +2029,7 @@ public void OnReset(object sender, TimerPhase e) {
Model.CurrentState.IsGameTimePaused = true;
splitsDone.Clear();
store.Reset();
HitsReset();
if (failedValues.Count > 0) {
WriteLog("---------Splits without match-------------------");
foreach (var value in failedValues) {
Expand All @@ -1949,6 +2050,7 @@ public void OnStart(object sender, EventArgs e) {
state = 0;
Model.CurrentState.IsGameTimePaused = true;
Model.CurrentState.SetGameTime(Model.CurrentState.CurrentTime.RealTime);
HitsIndexChanged();
splitsDone.Clear();
store.Reset();
failedValues.Clear();
Expand All @@ -1958,15 +2060,18 @@ public void OnStart(object sender, EventArgs e) {
}
public void OnUndoSplit(object sender, EventArgs e) {
currentSplit--;
HitsIndexChanged();
//if (!settings.Ordered) splitsDone.Remove(lastSplitDone); Reminder of THIS BREAKS THINGS
state = 0;
}
public void OnSkipSplit(object sender, EventArgs e) {
currentSplit++;
HitsIndexChanged();
state = 0;
}
public void OnSplit(object sender, EventArgs e) {
currentSplit++;
HitsIndexChanged();
store.SplitThisTransition = true;
store.Update();

Expand Down
14 changes: 13 additions & 1 deletion HollowKnightMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public partial class HollowKnightMemory {
public bool IsHooked { get; set; }
private DateTime lastHooked;
private int uiManager, inputHandler, cameraCtrl, gameState, heroController, camTarget, camMode, camTMode, camDest, menuState, uiState, achievementHandler;
private int heroAccepting, actorState, transistionState, camTeleport, playerData, debugInfo, tilemapDirty, cState, sceneName, nextSceneName, hazardRespawning, onGround, spellquake;
private int heroAccepting, actorState, transistionState, camTeleport, playerData, debugInfo, tilemapDirty, cState, sceneName, nextSceneName, hazardDeath, hazardRespawning, onGround, recoilFrozen, spellquake;
//private int sceneData, awardAchievementEvent;
private Version lastVersion;

Expand Down Expand Up @@ -59,8 +59,10 @@ private void UpdatedPointer(ProgramPointer pointer) {
heroAccepting = 0x457;
actorState = 0x374;
transistionState = 0x37c;
hazardDeath = 0x25; // best guess, TODO actually check
hazardRespawning = 0x26;
onGround = 0x9;
recoilFrozen = 0x28; // best guess, TODO actually check
spellquake = 0x37;

int versionString = 0x1c;
Expand Down Expand Up @@ -100,8 +102,10 @@ private void UpdatedPointer(ProgramPointer pointer) {
heroAccepting = 0x6e7;

//HeroControllerStates
hazardDeath = 0x2d;
hazardRespawning = 0x2e;
onGround = 0x11;
recoilFrozen = 0x30;
spellquake = 0x3f;

versionString = 0x38;
Expand Down Expand Up @@ -430,6 +434,10 @@ public bool TileMapDirty() {
//GameManager._instance.tileMapDirty
return gameManager.Read<bool>(Program, 0x0, tilemapDirty);
}
public bool HazardDeath() {
//GameManager._instance.hero_ctrl.cState.hazardDeath
return gameManager.Read<bool>(Program, 0x0, heroController, cState, hazardDeath);
}
public bool HazardRespawning() {
//GameManager._instance.hero_ctrl.cState.hazardRespawning
return gameManager.Read<bool>(Program, 0x0, heroController, cState, hazardRespawning);
Expand All @@ -438,6 +446,10 @@ public bool OnGround() {
//GameManager._instance.hero_ctrl.cState.onGround
return gameManager.Read<bool>(Program, 0x0, heroController, cState, onGround);
}
public bool RecoilFrozen() {
//GameManager._instance.hero_ctrl.cState.recoilFrozen
return gameManager.Read<bool>(Program, 0x0, heroController, cState, recoilFrozen);
}
public bool Spellquake() {
//GameManager._instance.hero_ctrl.cState.spellquake
return gameManager.Read<bool>(Program, 0x0, heroController, cState, spellquake);
Expand Down
38 changes: 31 additions & 7 deletions HollowKnightSettings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading