Skip to content

Commit

Permalink
Merge pull request #2 from flibber-hk/take-5-vt-vdash
Browse files Browse the repository at this point in the history
Take 5 vt vdash
  • Loading branch information
flibber-hk authored Jan 24, 2022
2 parents bbde109 + 03c4591 commit 8806ed1
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 23 deletions.
40 changes: 40 additions & 0 deletions SkillUpgrades/IC/ItemChangerInterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using GlobalEnums;
using ItemChanger;
using ItemChanger.Modules;
using ItemChanger.UIDefs;
using SkillUpgrades.IC.Items;

Expand Down Expand Up @@ -37,6 +38,45 @@ public static class ItemChangerInterop
public static void HookItemChanger()
{
DefineSkillUpgradeUnlockItems();
Events.AfterStartNewGame += ReflectOneways;
}

/// <summary>
/// If x -> y is a one way, and the one way transitions are coupled, then also have y -> x.
/// Check for coupled through the CompletionPercentOverride module; this is enabled in rando,
/// and in non-rando we can expect users to override these transitions themselves if they want
/// </summary>
private static void ReflectOneways()
{
if (ItemChangerMod.Modules.Get<CompletionPercentOverride>() is CompletionPercentOverride cpo && cpo.CoupledTransitions)
{
List<(string scene, string gate)> OneWayTransitions = new()
{
(SceneNames.Cliffs_02, "bot2"),
(SceneNames.Cliffs_02, "right1"),
(SceneNames.Mines_34, "bot2"),
(SceneNames.Mines_34, "left1"),
(SceneNames.Deepnest_East_07, "bot1"),
(SceneNames.Fungus2_30, "bot1"),
(SceneNames.Deepnest_01, "bot2"),
(SceneNames.Mines_28, "bot1"),
};

foreach ((string scene, string gate) in OneWayTransitions)
{
Transition source = new(scene, gate);

if (ItemChanger.Internal.Ref.Settings.TransitionOverrides.TryGetValue(source, out ITransition t)
&& t is Transition target
&& !ItemChanger.Internal.Ref.Settings.TransitionOverrides.ContainsKey(target))
{
ItemChangerMod.AddTransitionOverride(target, source);
cpo.SetTransitionWeight(target, 0);
}
}
}


}

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions SkillUpgrades/Skills/HorizontalDive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ internal void ResetQuakeAngle()

private void AllowHorizontalQuakeEntry(ILContext il)
{
ILCursor cursor = new ILCursor(il);
ILCursor cursor = new(il);

// slightly cursed code, because more involved modifications to IL code are fairly cursed
while (cursor.TryGotoNext
Expand Down Expand Up @@ -204,7 +204,7 @@ private void ModifyQuakeFSM(On.HeroController.orig_Start orig, HeroController se
#region Velocity values
void ModifyQuakeDownState(FsmState s)
{
ExecuteLambda setCCSevent = new ExecuteLambda(() =>
FsmStateAction setCCSevent = new ExecuteLambda(() =>
{
CheckCollisionSide ccs = s.GetActionOfType<CheckCollisionSide>();
FsmEvent heroLanded = FsmEvent.GetFsmEvent("HERO LANDED");
Expand Down Expand Up @@ -238,7 +238,7 @@ void ModifyQuakeDownState(FsmState s)
setvel.x = hSpeed;
setvel.y = vSpeed;

DecideToStopQuake decideToStop = new DecideToStopQuake(hSpeed, vSpeed);
FsmStateAction decideToStop = new DecideToStopQuake(hSpeed, vSpeed);

s.Actions = new FsmStateAction[]
{
Expand Down
181 changes: 161 additions & 20 deletions SkillUpgrades/Skills/VerticalSuperdash.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using GlobalEnums;
using HutongGames.PlayMaker;
using HutongGames.PlayMaker.Actions;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using MonoMod.Utils;
using UnityEngine;
using UnityEngine.SceneManagement;
using SkillUpgrades.FsmStateActions;
using SkillUpgrades.Util;

Expand All @@ -21,19 +29,145 @@ public class VerticalSuperdash : AbstractSkillUpgrade

public override string Description => "Toggle whether Crystal Heart can be used in non-horizontal directions";

private static readonly FastReflectionDelegate finishedEnteringScene = typeof(HeroController)
.GetMethod("FinishedEnteringScene", BindingFlags.Instance | BindingFlags.NonPublic)
.CreateFastDelegate();
private static void FinishedEnteringScene(HeroController hero, bool setHazardMarker, bool preventRunBob)
{
finishedEnteringScene.Invoke(hero, setHazardMarker, preventRunBob);
}

#region Cached Compiler-Generated EnterScene related infos
private static readonly MethodInfo heroEnterSceneMethod = typeof(HeroController)
.GetMethod(nameof(HeroController.EnterScene))
.GetStateMachineTarget();

private static readonly Type heroEnterSceneIteratorType = heroEnterSceneMethod.DeclaringType;

private static readonly FieldInfo HeroEnterSceneIteratorStateField = heroEnterSceneIteratorType
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.First(x => x.Name.Contains("state"));

private static int GetEnterSceneState(IEnumerator e) => (int)HeroEnterSceneIteratorStateField.GetValue(e);
#endregion

private ILHook _hook;

protected override void StartUpInitialize()
{
On.CameraTarget.Update += FixVerticalCamera;
On.GameManager.FinishedEnteringScene += DisableUpwardOneways;
On.HeroController.Start += ModifySuperdashFsm;

// Don't play weird animations when they should be cdashing
On.HeroAnimationController.canPlayTurn += FixCdashAnimation;
On.HeroAnimationController.PlayFromFrame += DontPlaySuperdash;
}
protected override void RepeatableInitialize()
{
// We need to move the entry coordinates for non-vertical oneways (Mines_34, Cliffs_02), and the TransitionPoint.entryOffset
// is not used for horizontal transitions
_hook = new(heroEnterSceneMethod, RepairHorizontalOneways);
// The colliders of upward oneways are disabled (except for Tutorial_01[top1]) so we need to enable them
UnityEngine.SceneManagement.SceneManager.activeSceneChanged += ActivateUpwardOneways;
// Complicated function to allow different behaviour when they enter scene from below with a cdash
On.HeroController.EnterScene += EnableTransitionCdash;
}
protected override void Unload()
{
_hook?.Dispose();
_hook = null;

UnityEngine.SceneManagement.SceneManager.activeSceneChanged -= ActivateUpwardOneways;
On.HeroController.EnterScene -= EnableTransitionCdash;
}

private void RepairHorizontalOneways(ILContext il)
{
ILCursor cursor = new(il);

cursor.GotoNext(i => i.MatchLdfld<HeroController>(nameof(HeroController.gatePosition)), i => i.MatchLdcI4(2));
cursor.GotoNext(MoveType.After, i => i.MatchCallvirt<HeroController>("FindGroundPointY"));
cursor.EmitDelegate<Func<float, float>>(x => GameManager.instance.sceneName == ItemChanger.SceneNames.Mines_34 ? 54.4f : x);

cursor.GotoNext(i => i.MatchLdfld<HeroController>(nameof(HeroController.gatePosition)), i => i.MatchLdcI4(1));
cursor.GotoNext(MoveType.After, i => i.MatchCallvirt<HeroController>("FindGroundPointY"));
cursor.EmitDelegate<Func<float, float>>(x => GameManager.instance.sceneName == ItemChanger.SceneNames.Cliffs_02 ? 28.4f : x);
}

private void DontPlaySuperdash(On.HeroAnimationController.orig_PlayFromFrame orig, HeroAnimationController self, string clipName, int frame)
{
// This only matters when cdashing out of an upward transition, but there's no reason to play this anim anyway
if (clipName == "Airborne" && HeroController.instance.cState.superDashing)
{
return;
}
orig(self, clipName, frame);
}

private void ActivateUpwardOneways(Scene _, Scene scene)
{
GameObject upwardOneway = scene.name switch
{
ItemChanger.SceneNames.RestingGrounds_02 => scene.GetRootGameObjects().First(x => x.name == "top1"),
ItemChanger.SceneNames.Mines_13 => scene.GetRootGameObjects().First(x => x.name == "top1"),
ItemChanger.SceneNames.Mines_23 => scene.GetRootGameObjects().First(x => x.name == "top1"),
ItemChanger.SceneNames.Town => scene.GetRootGameObjects().First(x => x.name == "_Transition Gates").transform.Find("top1").gameObject,
ItemChanger.SceneNames.Tutorial_01 => scene.GetRootGameObjects().First(x => x.name == "_Transition Gates").transform.Find("top1").gameObject,
ItemChanger.SceneNames.Fungus2_25 => scene.GetRootGameObjects().First(x => x.name == "top2"),
ItemChanger.SceneNames.Deepnest_East_03 => scene.GetRootGameObjects().First(x => x.name == "top2"),
ItemChanger.SceneNames.Deepnest_01b => scene.GetRootGameObjects().First(x => x.name == "_Transition Gates").transform.Find("top2").gameObject,
_ => null
};

if (upwardOneway != null)
{
upwardOneway.GetComponent<Collider2D>().enabled = true;
}
}

private bool FixCdashAnimation(On.HeroAnimationController.orig_canPlayTurn orig, HeroAnimationController self)
{
return !HeroController.instance.cState.superDashing && orig(self);
}

private IEnumerator EnableTransitionCdash(On.HeroController.orig_EnterScene orig, HeroController self, TransitionPoint enterGate, float delayBeforeEnter)
{
IEnumerator e = orig(self, enterGate, delayBeforeEnter);

if (e.GetType() != heroEnterSceneIteratorType)
{
LogWarn("Editing EnterScene blocked by a mod in assembly:\n" + e.GetType().Assembly.FullName);
yield return e;
}

bool exitedSuperdashing = self.exitedSuperDashing;

while (e.MoveNext())
{
yield return e.Current;

if (GetEnterSceneState(e) == 10 && exitedSuperdashing)
{
if (enterGate.GetGatePosition() != GatePosition.bottom)
{
LogError($"Unexpected Gate Position: {enterGate.GetGatePosition()}");
}

if (!enterGate.customFade)
{
GameManager.instance.FadeSceneIn();
}

self.exitedSuperDashing = true;
self.IgnoreInput();
self.proxyFSM.SendEvent("HeroCtrl-EnterSuperDash");
yield return new WaitForSeconds(0.25f);
FinishedEnteringScene(self, true, false);
yield break;
}
}
}

/// <summary>
/// The angle the knight is superdashing, measured anticlockwise when the knight is facing left and clockwise when facing right
/// </summary>
Expand Down Expand Up @@ -75,21 +209,6 @@ private void FixVerticalCamera(On.CameraTarget.orig_Update orig, CameraTarget se
self.cameraCtrl.lookOffset += Math.Abs(self.dashOffset) * Mathf.Sin(SuperdashAngle * Mathf.PI / 180);
self.dashOffset *= Mathf.Cos(SuperdashAngle * Mathf.PI / 180);
}
// Deactivate upward oneway transitions after spawning in so the player doesn't accidentally
// softlock by vc-ing into them
private void DisableUpwardOneways(On.GameManager.orig_FinishedEnteringScene orig, GameManager self)
{
orig(self);

switch (self.sceneName)
{
// The KP top transition is the only one that needs to be disabled; the others have collision
case "Tutorial_01":
if (GameObject.Find("top1") is GameObject topTransition)
topTransition.SetActive(false);
break;
}
}

private void ModifySuperdashFsm(On.HeroController.orig_Start orig, HeroController self)
{
Expand Down Expand Up @@ -203,7 +322,7 @@ void monitorDirectionalInputs(bool firstFrame)
{
HeroController.instance.FaceLeft();
}

}
else if (!ia.left.IsPressed && ia.right.IsPressed)
{
Expand Down Expand Up @@ -237,14 +356,14 @@ void monitorDirectionalInputs(bool firstFrame)
}
}

ExecuteLambda setVelocityVariablesAction = new ExecuteLambda(setVelocityVariables);
FsmStateAction setVelocityVariablesAction = new ExecuteLambda(setVelocityVariables);

SetVelocity2d setVel = dashing.GetActionOfType<SetVelocity2d>();
setVel.x = hSpeed;
setVel.y = vSpeed;

DecideToStopSuperdash decideToStop = new DecideToStopSuperdash(hSpeed, vSpeed, zeroLast);
ExecuteLambdaEveryFrame turnInMidair = new ExecuteLambdaEveryFrame(monitorDirectionalInputs);
FsmStateAction decideToStop = new DecideToStopSuperdash(hSpeed, vSpeed, zeroLast);
FsmStateAction turnInMidair = new ExecuteLambdaEveryFrame(monitorDirectionalInputs);

dashing.Actions = new FsmStateAction[]
{
Expand All @@ -269,6 +388,28 @@ void monitorDirectionalInputs(bool firstFrame)
cancelable.Actions[6], // (same as above)
turnInMidair,
};

void SetSuperdashAngleOnEntry()
{
switch (HeroController.instance.sceneEntryGate.GetGatePosition())
{
case GatePosition.bottom: SuperdashAngle = -90f; break;
case GatePosition.top: SuperdashAngle = 90f; break;
}
HeroController.instance.RotateHero(SuperdashAngle);
}
fsm.GetState("Enter Velocity").Actions = new FsmStateAction[]
{
new ExecuteLambda(SetSuperdashAngleOnEntry),
new SetVelocity2d()
{
gameObject = setVel.gameObject,
vector = setVel.vector,
x = setVel.x,
y = setVel.y,
everyFrame = false
}
};
#endregion

#region Reset Vertical Charge variable
Expand Down

0 comments on commit 8806ed1

Please sign in to comment.