diff --git a/Braver.Core/Util.cs b/Braver.Core/Util.cs index 4ba72b2..99e0e3e 100644 --- a/Braver.Core/Util.cs +++ b/Braver.Core/Util.cs @@ -25,6 +25,10 @@ namespace Braver { t1 = t2; t2 = t; } + + public static T? MapToNull(T value, T nullPlaceholder) where T : struct { + return value.Equals(nullPlaceholder) ? null : value; + } } public class F7Exception : Exception { diff --git a/Braver/Field/FieldModel.cs b/Braver/Field/FieldModel.cs index 762620a..1585401 100644 --- a/Braver/Field/FieldModel.cs +++ b/Braver/Field/FieldModel.cs @@ -4,14 +4,12 @@ // // SPDX-License-Identifier: EPL-2.0 -using Braver.Plugins; using Ficedula.FF7; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; namespace Braver.Field { @@ -21,7 +19,7 @@ namespace Braver.Field { public int Frame { get; set; } public bool AnimationLoop { get; set; } public int StartFrame { get; set; } - public int EndFrame { get; set; } + public int? EndFrame { get; set; } public int CompletionCount { get; set; } } @@ -423,7 +421,8 @@ namespace Braver.Field { _shineRotation++; if (_animCountdown <= 0) { _animCountdown = 1; - if (AnimationState.Frame == AnimationState.EndFrame) { + int actualEnd = AnimationState.EndFrame ?? _animations[AnimationState.Animation].Frames.Count - 1; + if (AnimationState.Frame == actualEnd) { if (AnimationState.AnimationLoop) { AnimationState.Frame = AnimationState.StartFrame; AnimationState.CompletionCount++; @@ -435,8 +434,8 @@ namespace Braver.Field { } } - public void PlayAnimation(int animation, bool loop, float speed, int startFrame = 0, int endFrame = -1) { - if (endFrame >= _animations[animation].Frames.Count) { + public void PlayAnimation(int animation, bool loop, float speed, int startFrame = 0, int? endFrame = null) { + if ((endFrame ?? 0) >= _animations[animation].Frames.Count) { System.Diagnostics.Trace.WriteLine($"Clamping out of range animation frames {endFrame}->{_animations[animation].Frames.Count - 1}"); endFrame = _animations[animation].Frames.Count - 1; } @@ -446,7 +445,7 @@ namespace Braver.Field { AnimationSpeed = speed, StartFrame = startFrame, Frame = startFrame, - EndFrame = endFrame < 0 ? _animations[animation].Frames.Count - 1 : endFrame, + EndFrame = endFrame, }; _animCountdown = 1; } diff --git a/Braver/Field/FieldScreen.cs b/Braver/Field/FieldScreen.cs index ad32716..e59fee9 100644 --- a/Braver/Field/FieldScreen.cs +++ b/Braver/Field/FieldScreen.cs @@ -574,15 +574,15 @@ namespace Braver.Field { var highPosOnBG = ModelToBGPosition(Player.Model.Translation + new Vector3(0, 0, playerHeight)); var scroll = GetBGScroll(); var newScroll = scroll; - if (posOnBG.X > (scroll.x + 100)) - newScroll.x = (int)posOnBG.X - 100; - else if (posOnBG.X < (scroll.x - 100)) - newScroll.x = (int)posOnBG.X + 100; + if (posOnBG.X > (scroll.x + 50)) + newScroll.x = (int)posOnBG.X - 50; + else if (posOnBG.X < (scroll.x - 50)) + newScroll.x = (int)posOnBG.X + 50; - if (highPosOnBG.Y > (scroll.y + 85)) - newScroll.y = (int)highPosOnBG.Y - 85; - else if (posOnBG.Y < (scroll.y - 85)) - newScroll.y = (int)posOnBG.Y + 85; + if (highPosOnBG.Y > (scroll.y + 45)) + newScroll.y = (int)highPosOnBG.Y - 45; + else if (posOnBG.Y < (scroll.y - 45)) + newScroll.y = (int)posOnBG.Y + 45; newScroll = ClampBGScrollToViewport(newScroll.x, newScroll.y); @@ -1178,11 +1178,18 @@ namespace Braver.Field { //Now check if, for any of the models we're colliding with, we're not moving //clearly further away. If so, don't allow the move. foreach(var other in eMove.CollidingWith) { - double currentAngle = Math.Atan2(eMove.Model.Translation.Y - other.Model.Translation.Y, eMove.Model.Translation.X - other.Model.Translation.X), - moveAngle = Math.Atan2(newPosition.Y - other.Model.Translation.Y, newPosition.X - other.Model.Translation.X); + //Use law of cosines to work out the angle between our current position to the other + //object, and our current position to the new position. If the angle is less than 90, + //then we're heading towards the new object while colliding with it, so disallow the move. + //We don't just compare distances and allow any movement that ends up further away from + //the colliding object, because then we can potentially teleport through a small enough + //object! + float a = (other.Model.Translation - eMove.Model.Translation).Length(), + b = (newPosition - eMove.Model.Translation).Length(), + c = (other.Model.Translation - newPosition).Length(); + double C = Math.Acos((a * a + b * b - c * c) / (2 * a * b)); - double diff = ((currentAngle - moveAngle) + (Math.PI * 2)) % (2 * Math.PI); - if (diff >= Math.PI) + if (C < (Math.PI / 2)) return false; } } diff --git a/Braver/Field/VM.cs b/Braver/Field/VM.cs index c6d0e6a..73025a8 100644 --- a/Braver/Field/VM.cs +++ b/Braver/Field/VM.cs @@ -1228,17 +1228,16 @@ namespace Braver.Field { } private static OpResult DoAnim(Fiber f, Entity e, int anim, bool loop, float speed, int? startFrame, int? endFrame, bool restoreState) { - int start = startFrame ?? 0, - end = endFrame ?? -1; + int start = startFrame ?? 0; var model = e.Model; if ((model.AnimationState == null) || (model.AnimationState.Animation != anim) || (model.AnimationState.AnimationLoop != loop) || (model.AnimationState.StartFrame != start) || - ((model.AnimationState.EndFrame != end) && (end != -1)) || + (model.AnimationState.EndFrame != endFrame) || (model.AnimationState.AnimationSpeed != speed)) { e.OtherState["AnimPlaying"] = true; f.OtherState["AnimResume"] = model.AnimationState; - model.PlayAnimation(anim, loop, speed, start, end); + model.PlayAnimation(anim, loop, speed, start, endFrame); } else { if (model.AnimationState.CompletionCount > 0) { e.OtherState["AnimPlaying"] = false; diff --git a/Braver/Net/Field.cs b/Braver/Net/Field.cs index 648f266..7b9ab46 100644 --- a/Braver/Net/Field.cs +++ b/Braver/Net/Field.cs @@ -119,7 +119,7 @@ namespace Braver.Net { Animation = reader.GetInt(), AnimationLoop = reader.GetBool(), AnimationSpeed = reader.GetFloat(), - EndFrame = reader.GetInt(), + EndFrame = Utils.MapToNull(reader.GetInt(), -1), Frame = reader.GetInt(), StartFrame = reader.GetInt(), }; @@ -161,7 +161,7 @@ namespace Braver.Net { writer.Put(AnimationState.Animation); writer.Put(AnimationState.AnimationLoop); writer.Put(AnimationState.AnimationSpeed); - writer.Put(AnimationState.EndFrame); + writer.Put(AnimationState.EndFrame ?? -1); writer.Put(AnimationState.Frame); writer.Put(AnimationState.StartFrame); } diff --git a/Braver/TODO.txt b/Braver/TODO.txt index 38dee7d..92f631f 100644 --- a/Braver/TODO.txt +++ b/Braver/TODO.txt @@ -42,6 +42,8 @@ Field - model lighting looks a bit too bright - mds7_pb1 - Marlene's ladder command treats her as a player incorrectly - Tutorials don't actually display - mds7_w2 has multiple KAWAI opcodes to implement! + - nmkin_3 - animations when leaving ladder at top are sequenced wrong? + - nmkin_1 - background Z still not perfect Music looping works but still a noticeable break at the loop point diff --git a/Braver/UI/Splash.cs b/Braver/UI/Splash.cs index 9e5e49e..8a39794 100644 --- a/Braver/UI/Splash.cs +++ b/Braver/UI/Splash.cs @@ -127,6 +127,22 @@ namespace Braver.UI { //Game.ChangeScreen(this, new TestScreen()); //Game.ChangeScreen(this, new WorldMap.WMScreen(139348, 126329)); Battle.BattleScreen.Launch(Game, 324, Battle.BattleFlags.None); + /* + Game.ChangeScreen(this, new Field.FieldScreen( + new Ficedula.FF7.Field.FieldDestination { + X = 349, Y = -463, Triangle = 22, + Orientation = 124, + DestinationFieldID = 331, + } + /* + new Ficedula.FF7.Field.FieldDestination { + X = 7, Y = -107, Triangle = 21, + Orientation = 132, + DestinationFieldID = 335, + } + )); + */ + break; case 4: