diff --git a/Source/Actors/Player.cs b/Source/Actors/Player.cs index b4817f9..0edd2c6 100644 --- a/Source/Actors/Player.cs +++ b/Source/Actors/Player.cs @@ -129,7 +129,7 @@ public enum Events { Land }; // TAS: publicized public Vec3 Velocity => velocity; public Vec3 PreviousVelocity => previousVelocity; - private Vec3 velocity; + public Vec3 velocity; // TAS: publicized private Vec3 previousVelocity; private Vec3 groundNormal; public Vec3 platformVelocity; // TAS: publicized @@ -1043,9 +1043,9 @@ internal void Spring(Spring spring) private const float FootstepInterval = .3f; - private float tHoldJump; - private float holdJumpSpeed; - private bool autoJump; + public float tHoldJump; // TAS: publicized + public float holdJumpSpeed; // TAS: publicized + public bool autoJump; // TAS: publicized private float tNoMove; private float tFootstep; diff --git a/Source/TAS/Input/Commands/LoadCommand.cs b/Source/TAS/Input/Commands/LoadCommand.cs index e5f7a91..149c4e5 100644 --- a/Source/TAS/Input/Commands/LoadCommand.cs +++ b/Source/TAS/Input/Commands/LoadCommand.cs @@ -47,7 +47,7 @@ private static void LoadStrawbCmd(string[] args) if (!float.TryParse(args[2], out float targetFacing)) { - Manager.AbortTas($"Couldn't parse facing direction '{args[3]}'"); + Manager.AbortTas($"Couldn't parse facing direction '{args[2]}'"); return; } @@ -95,4 +95,71 @@ private static void LoadStrawbCmd(string[] args) FromBlack = new SpotlightWipe(), }); } + + [Command("LoadCassette", LegalInFullGame = false)] + private static void LoadCassetteCmd(string[] args) + { + if (args.Length != 3) + { + Manager.AbortTas("Level, Cassette IDs and Facing direction are required for the LoadCassette command"); + return; + } + + string cassetteMap = args[1]; + + if (!float.TryParse(args[2], out float targetFacing)) + { + Manager.AbortTas($"Couldn't parse facing direction '{args[3]}'"); + return; + } + + var entry = new World.EntryInfo() + { + Map = args[0], + CheckPoint = "Start", // Doesnt matter anyway + Submap = false, // TODO + Reason = World.EntryReasons.Entered, + }; + + // We need to change the current scene to the main menu, + // since otherwise an input on the first frame would get consumed by the previous scene. + if (Game.Instance.scenes.TryPop(out _)) + { + Game.Instance.scenes.Push(new Overworld(true)); + } + + Game.Instance.Goto(new Transition() + { + Mode = Transition.Modes.Replace, + Scene = () => + { + var world = new World(entry); + + // We need to search through 'adding', since they'll only get properly added on the first update call. + if (!world.adding.TryFirst(actor => actor is Player, out var playerActor) || playerActor is not Player player) + { + Manager.AbortTas($"Couldn't find player"); + return world; + } + if (!world.adding.TryFirst(actor => actor is Cassette c && c.Map == cassetteMap, out var cassette)) + { + Manager.AbortTas($"Couldn't parse cassette ID '{cassetteMap}'"); + return world; + } + + player.Position = cassette.Position - Vec3.UnitZ * 3; + player.velocity = Vec3.UnitZ * 25; + player.holdJumpSpeed = player.velocity.Z; + player.tHoldJump = .1f; + player.autoJump = true; + + player.Facing = player.targetFacing = new Vec2(MathF.Sin(targetFacing * Calc.DegToRad), -MathF.Cos(targetFacing * Calc.DegToRad)); + Manager.TASLevelRecord.CompletedSubMaps.Add(cassetteMap); + + return world; + }, + ToBlack = null, + FromBlack = new SpotlightWipe(), + }); + } }