private static void PreparePsychedelia(SongCues.Cue cue) { if (Config.enablePsychedelia) { if (cue.behavior == Target.TargetBehavior.Melee || cue.behavior == Target.TargetBehavior.ChainStart || cue.behavior == Target.TargetBehavior.Hold) { List <float> ticks = new List <float>(); if (cue.behavior == Target.TargetBehavior.ChainStart) { LookForEndOfChain(cue, ticks); } else { LookForLastBehavior(cue, new Target.TargetBehavior[] { Target.TargetBehavior.Melee }, ticks); } if (cue.behavior == Target.TargetBehavior.Hold && cue.tickLength >= 1920f) { //MelonCoroutines.Stop(psyToken); //psyToken = MelonCoroutines.Start(DoPsychedelia(AudioDriver.I.mCachedTick + cue.tickLength - 960f)); psyEvents.Add(new PsyEvent(cue.tick, cue.tick + cue.tickLength - 960f)); } else if (ticks[0] - cue.tick >= 1920f && cue.behavior == Target.TargetBehavior.Melee) { //MelonCoroutines.Stop(psyToken); //psyToken = MelonCoroutines.Start(DoPsychedelia(ticks[0] - 960f)); psyEvents.Add(new PsyEvent(cue.tick, ticks[0] - 960f)); } } } }
private static float CalculateIntensity(float startTick, float endTick, List <SongCues.Cue> cues) { float intensity = 0f; bool indexSet = false; for (int i = startIndex; i < cues.Count; i++) { SongCues.Cue cue = SongCues.I.mCues.cues[i]; if (cue.tick >= endTick) { break; } if (cue.tick >= startTick && cue.tick < endTick) { intensity += GetTargetAmount((Hitsound)cue.velocity, cue.behavior); if (!indexSet) { indexSet = true; startIndex = i; } } } intensity /= AudioDriver.TickSpanToMs(SongDataHolder.I.songData, startTick, endTick); intensity *= 1000f; return(intensity); }
private static void RemoveChainCues(Target.TargetHandType handType) { int length = songCues.Count - 1; int index = 0; for (int i = 0; i < length; i++) { SongCues.Cue cue = songCues[index]; if (cue.handType == handType) { if (cue.behavior == Target.TargetBehavior.Chain) { songCues.RemoveAt(index); } else { return; } } else { index++; } } }
private static void Postfix(Telegraph __instance, SongCues.Cue cue, float animationSpeed) { if (Config.HiddenClouds == true || ForceEnable == true || Config.CleanStacks) { if (cue.behavior == Target.TargetBehavior.Melee || cue.behavior == Target.TargetBehavior.Dodge) { return; } if (Config.CleanStacks) { if (cue.nextCue is null || cue.behavior == Target.TargetBehavior.ChainStart || cue.behavior == Target.TargetBehavior.Chain) { return; } if (cue.nextCue.pitch == cue.pitch && (cue.nextCue.tick - cue.tick < 480)) { __instance.cloud.enabled = false; hideNextCloud = true; return; } if (hideNextCloud) { hideNextCloud = false; __instance.cloud.enabled = false; } } else { __instance.cloud.enabled = false; } } }
private static void LookForLastBehavior(SongCues.Cue cue, Target.TargetBehavior[] behaviors, List <float> ticks) { if (cue.nextCue is null) { ticks.Add(cue.tick); return; } for (int i = 0; i < behaviors.Length; i++) { if (cue.nextCue.behavior == behaviors[i]) { if (cue.behavior == Target.TargetBehavior.Hold && cue.nextCue.behavior == Target.TargetBehavior.Hold && cue.tick == cue.nextCue.tick) { continue; } if (cue.behavior == Target.TargetBehavior.Melee && cue.nextCue.behavior == Target.TargetBehavior.Melee && cue.tick == cue.nextCue.tick) { continue; } LookForLastBehavior(cue.nextCue, behaviors, ticks); return; } } ticks.Add(cue.nextCue.tick); }
private void RecursiveAdd(SongCues.Cue cue, List <SongCues.Cue> chain) { chain.Add(cue); if (cue.chainNext != null) { RecursiveAdd(cue.chainNext, chain); } }
Vector2 GetTrueCoordinates(SongCues.Cue cue) { float x = cue.pitch % 12; float y = (int)(cue.pitch / 12); x += cue.gridOffset.x; y += cue.gridOffset.y; return(new Vector2(x, y)); }
private void RecursiveGetChain(SongCues.Cue cue, List <SongCues.Cue> chain, List <int> pitches) { chain.Add(cue); pitches.Add(cue.pitch); if (cue.chainNext != null) { RecursiveGetChain(cue.chainNext, chain, pitches); } }
private void pollSongState() { if (this.songPlaying) { string songClass = "custom"; if (this.songData.IsCoreSong()) { songClass = "ost"; } if (this.songData.dlc) { songClass = "dlc"; } if (this.songData.extrasSong) { songClass = "extras"; } // We don't want to calculate the ticks to the end of the song, it keeps playing! // Instead get the last target (plus its length) as the end ticks UnhollowerBaseLib.Il2CppReferenceArray <SongCues.Cue> cues = AudicaGameStateManager.songCues.mCues.cues; SongCues.Cue endCue = cues[cues.Length - 1]; float songEndTicks = endCue.tick + endCue.tickLength; float currentTick = AudicaGameStateManager.scoreKeeper.mLastTick; float totalTimeMs = this.songCalculator.SongLengthMilliseconds; float currentTimeMs = this.songCalculator.GetSongPositionMilliseconds(currentTick); float remainingTimeMs = totalTimeMs - currentTimeMs; this.songState.songId = this.songData.songID; this.songState.songName = this.songData.title; this.songState.songArtist = this.songData.artist; this.songState.songAuthor = this.songData.author; this.songState.difficulty = KataConfig.GetDifficultyName(AudicaGameStateManager.config.GetDifficulty()); this.songState.classification = songClass; this.songState.songLength = TimeSpan.FromMilliseconds(Convert.ToInt64(totalTimeMs)).ToString(); this.songState.timeElapsed = TimeSpan.FromMilliseconds(Convert.ToInt64(currentTimeMs)).ToString(); this.songState.timeRemaining = TimeSpan.FromMilliseconds(Convert.ToInt64(remainingTimeMs)).ToString(); this.songState.progress = currentTimeMs / totalTimeMs; this.songState.currentTick = currentTick; this.songState.ticksTotal = songEndTicks; this.songState.songSpeed = KataConfig.GetCueDartSpeedMultiplier(); // TODO: not a clue what this value actually is but it's not the speed multiplier! this.songState.health = AudicaGameStateManager.scoreKeeper.GetHealth(); this.songState.score = AudicaGameStateManager.scoreKeeper.mScore; this.songState.scoreMultiplier = AudicaGameStateManager.scoreKeeper.GetRawMultiplier(); this.songState.streak = AudicaGameStateManager.scoreKeeper.GetStreak(); this.songState.highScore = AudicaGameStateManager.scoreKeeper.GetHighScore(); this.songState.isNoFailMode = AudicaGameStateManager.prefs.NoFail.mVal; this.songState.isPracticeMode = AudicaGameStateManager.config.practiceMode; this.songState.isFullComboSoFar = AudicaGameStateManager.scoreKeeper.GetIsFullComboSoFar(); this.songState.modifiers = AudicaGameStateManager.modifiers.GetCurrentModifiers() .Select((GameplayModifiers.Modifier mod) => GameplayModifiers.GetModifierString(mod)) .ToList <string>(); } }
public AudicaTargetFailState TargetMissAim() { AudicaTargetFailState targetMiss = new AudicaTargetFailState(); SongCues.Cue cue = AudicaTargetStateManager.targetTracker.mLastEitherHandTarget.target.GetCue(); targetMiss.targetIndex = cue.index; targetMiss.type = this.cueToTargetType(cue); targetMiss.hand = this.cueToHand(cue); targetMiss.reason = "aim"; return(targetMiss); }
private void SpawnMine(float tickStart) { if (tickStart > SongCues.I.GetLastCueStartTick()) { return; } float x = UnityEngine.Random.Range(minOffset.x, maxOffset.x); float y = UnityEngine.Random.Range(minOffset.y, maxOffset.y); Vector2 offset = new Vector2(x, y); SongCues.Cue cue = new SongCues.Cue((int)tickStart, 120, 100, 3, Target.TargetHandType.None, Target.TargetBehavior.Dodge, offset); spawner.SpawnCue(cue); }
public AudicaTargetFailState TargetMissEarlyLate(float tick) { AudicaTargetFailState targetMiss = new AudicaTargetFailState(); SongCues.Cue cue = AudicaTargetStateManager.targetTracker.mLastEitherHandTarget.target.GetCue(); targetMiss.targetIndex = cue.index; targetMiss.type = this.cueToTargetType(cue); targetMiss.hand = this.cueToHand(cue); targetMiss.reason = tick < cue.tick ? "early" : "late"; return(targetMiss); }
private static void Postfix(Telegraph __instance, SongCues.Cue cue, float animationSpeed) { if (!hideTeles) { return; } if (cue.behavior == Target.TargetBehavior.Melee || cue.behavior == Target.TargetBehavior.Dodge) { return; } __instance.circleMesh.enabled = false; __instance.cloud.enabled = false; }
private static void Postfix(ScoreKeeper __instance, ref SongCues.Cue cue) { if (KataConfig.I.practiceMode) { return; } if (GrindMode.waitForRestart) { return; } if (GrindMode.grindMode && Config.highscoreMode && !GrindMode.highscoreIsSetup) { GrindMode.SetHighscore(ScoreKeeper.I.GetHighScore()); } if (cue is null) { return; } if (!GrindMode.grindMode || KataConfig.I.NoFail()) { return; } if (Config.highscoreMode) { //if (!GrindMode.skipSetScoreMiss) GrindMode.SetCurrentScore(__instance.mScore, __instance.mStreak, __instance.mMultiplier, cue, true); //GrindMode.skipSetScoreMiss = !GrindMode.skipSetScoreMiss; return; } if (!Config.includeChainSustainBreak) { if (cue.behavior == Target.TargetBehavior.Chain) { //MelonModLogger.Log("Chain break! Ignoring."); return; } else if (cue.behavior == Target.TargetBehavior.Hold && cue.target.mSustainFailed) { //MelonModLogger.Log("Sustain break! Ignoring."); return; } } GrindMode.ReportMiss(cue); }
public AudicaTargetHitState TargetHit(GameplayStats gameplayStats, SongCues.Cue cue, Vector2 targetHitPos) { AudicaTargetHitState targetHit = new AudicaTargetHitState(); targetHit.targetIndex = cue.index; targetHit.type = this.cueToTargetType(cue); targetHit.hand = this.cueToHand(cue); targetHit.timingScore = gameplayStats.GetLastTimingScore(); targetHit.aimScore = gameplayStats.GetLastAimScore(); targetHit.score = targetHit.timingScore + targetHit.aimScore; // TODO: may need to multiply by combo? Need to test targetHit.tick = cue.tick; targetHit.targetHitPosition = targetHitPos; return(targetHit); }
private string cueToHand(SongCues.Cue cue) { string hand = ""; switch (cue.handType) { case Target.TargetHandType.Left: hand = "left"; break; case Target.TargetHandType.Right: hand = "right"; break; case Target.TargetHandType.Either: hand = "either"; break; case Target.TargetHandType.None: hand = "none"; break; } return(hand); }
private static void LookForEndOfChain(SongCues.Cue cue, List <float> ticks) { if (cue.nextCue is null) { ticks.Add(cue.tick); return; } if (cue.nextCue.behavior == Target.TargetBehavior.Chain) { LookForEndOfChain(cue.nextCue, ticks); return; } ticks.Add(cue.nextCue.tick); }
private static void Postfix(ScoreKeeper __instance, ref SongCues.Cue cue) { if (KataConfig.I.practiceMode) { return; } if (!GrindMode.grindMode || KataConfig.I.NoFail()) { return; } if (Config.highscoreMode) { if (!GrindMode.highscoreIsSetup) { GrindMode.SetHighscore(ScoreKeeper.I.GetHighScore()); } // if (!GrindMode.skipSetScoreSuccess) GrindMode.SetCurrentScore(__instance.mScore, __instance.mStreak, __instance.mMultiplier, cue); //GrindMode.skipSetScoreSuccess = !GrindMode.skipSetScoreSuccess; return; } if (GrindMode.chainLH) { if (cue.handType == Target.TargetHandType.Left) { GrindMode.chainLH = false; } } else if (GrindMode.chainRH) { if (cue.handType == Target.TargetHandType.Right) { GrindMode.chainRH = false; } } }
public static void ReportMiss(SongCues.Cue cue) { if (Config.highscoreMode) { return; } //return here, else every single chain node would count as an individual miss if (lastTarget.behavior == Target.TargetBehavior.Chain && cue.behavior == Target.TargetBehavior.Chain && lastTarget.handType == cue.handType) { return; } if (cue.behavior == Target.TargetBehavior.Chain || cue.behavior == Target.TargetBehavior.ChainStart) { if (cue.handType == Target.TargetHandType.Left) { chainLH = true; } else { chainRH = true; } } else if (chainLH) { chainLH = false; } else if (chainRH) { chainRH = false; } lastTarget = cue; reportedCues.Add(cue); missCount++; CheckFail(); }
private string cueToTargetType(SongCues.Cue cue) { string type = ""; switch (cue.behavior) { case Target.TargetBehavior.Melee: type = "melee"; break; case Target.TargetBehavior.Standard: type = "standard"; break; case Target.TargetBehavior.Hold: type = "sustain"; break; case Target.TargetBehavior.Vertical: type = "vertical"; break; case Target.TargetBehavior.Horizontal: type = "horizontal"; break; case Target.TargetBehavior.ChainStart: type = "chain-start"; break; case Target.TargetBehavior.Chain: type = "chain"; break; case Target.TargetBehavior.Dodge: type = "bomb"; break; } return(type); }
private void Precalc() { this.song = SongDataHolder.I.songData; UnhollowerBaseLib.Il2CppReferenceArray <SongCues.Cue> cues = AudicaGameStateManager.songCues.mCues.cues; SongCues.Cue endCue = cues[cues.Length - 1]; float endTick = endCue.tick + endCue.tickLength; this.songLengthMs = 0; for (int i = 0; i < song.tempos.Length; i++) { float startChunkTick = song.tempos[i].tick; float endChunkTick = endTick; // if it's NOT the last tempo change, grab the tick from the next one instead. if (i != song.tempos.Length - 1) { endChunkTick = song.tempos[i + 1].tick; } // complete chunk length in ticks float chunkTickLength = endChunkTick - startChunkTick; // ms accumulator float chunkMilliseconds = GetTicksMillisconds(chunkTickLength, song.tempos[i].tempo); this.songLengthMs += chunkMilliseconds; // cache ChunkCache chunk = new ChunkCache(); chunk.startTick = startChunkTick; chunk.endTick = endChunkTick; chunk.lengthMs = chunkMilliseconds; this.chunkCache.Add(chunk); } }
public static void Postfix(ref GameplayStats __instance, ref SongCues.Cue cue, ref Vector2 targetHitPos) { MelonLoader.MelonModLogger.Log("Target Hit! " + targetHitPos.ToString()); AudicaTargetHitState targetHit = AudicaHTTPStatus.AudicaTargetState.TargetHit(__instance, cue, targetHitPos); // TODO: feed output into JSON parser then to HTTP server as websocket event }
public static void SetCurrentScore(int score, int streak, int multiplier, SongCues.Cue cue, bool miss = false) { if (waitForRestart) { return; } if (cue.behavior == Target.TargetBehavior.Chain) { lastTarget = cue; if (cue.nextCue.behavior == Target.TargetBehavior.Chain) { return; } else { if (chainLH && cue.handType == Target.TargetHandType.Left) { chainLH = false; } else if (chainRH && cue.handType == Target.TargetHandType.Right) { chainRH = false; } RemoveChainCues(cue.handType); } } if (cue.behavior == Target.TargetBehavior.ChainStart) { if (cue.handType == Target.TargetHandType.Left) { chainLH = true; } else { chainRH = true; } } lastTarget = cue; int length = songCues.Count - 1; if (chainLH) { int index = 0; for (int i = 0; i < length; i++) { SongCues.Cue c = songCues[i]; if (c.behavior == Target.TargetBehavior.Chain && c.handType == Target.TargetHandType.Left) { index++; } else { songCues.RemoveAt(index); break; } } } else if (chainRH) { int index = 0; for (int i = 0; i < length; i++) { SongCues.Cue c = songCues[i]; if (c.behavior == Target.TargetBehavior.Chain && c.handType == Target.TargetHandType.Right) { index++; } else { songCues.RemoveAt(index); break; } } } else { if (cue.behavior != Target.TargetBehavior.Chain) { songCues.RemoveAt(0); } } currentScore = score; currentMultiplier = multiplier; currentStreak = streak; CalculateMaxPossibleScore(); }
private static void Prefix(Target __instance, TargetSpawner.SpawnInfo info, SongCues.Cue cue) { if (!updateChainColor) { return; } if (cue.behavior != Target.TargetBehavior.Chain) { return; } if (cue.handType == Target.TargetHandType.Left) { __instance.chainLine.startColor = PlayerPreferences.I.GunColorLeft.Get() / 2; __instance.chainLine.endColor = PlayerPreferences.I.GunColorLeft.Get() / 2; } else { __instance.chainLine.startColor = PlayerPreferences.I.GunColorRight.Get() / 2; __instance.chainLine.endColor = PlayerPreferences.I.GunColorRight.Get() / 2; } }