mirror of
https://github.com/ficed/Braver.git
synced 2024-11-23 21:29:48 +00:00
Field
VM: Implement CANIM2, MMBLK, FMUSC, MULCK, PMVIE, MOVIE, MVIEF, SCR2DC, BTLON, BTLMD VM: Implement AKAO, AKAO2, FADE, NFADE partially Overlay working, use to implement auto fade in only when appropriate Movie playback mostly working (!)
This commit is contained in:
parent
a35d7dab14
commit
11293aa771
@ -56,6 +56,7 @@ namespace Braver {
|
||||
Party3 = 0x40,
|
||||
|
||||
Available = 0x100,
|
||||
Locked = 0x200,
|
||||
|
||||
ANY_PARTY_SLOT = Party1 | Party2 | Party3,
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<ApplicationIcon>Icon.ico</ApplicationIcon>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="Microsoft.Xna.Framework.Content.ContentTypeReader" Visible="false" />
|
||||
|
@ -31,6 +31,7 @@ namespace Braver {
|
||||
public Audio Audio { get; }
|
||||
public Screen Screen => _screens.Peek();
|
||||
|
||||
public string FFMpegPath { get; private set; } //TODO - better place to put/calculate this?
|
||||
|
||||
private Dictionary<string, string> _prefs;
|
||||
|
||||
@ -64,6 +65,7 @@ namespace Braver {
|
||||
L = _data[category] = new();
|
||||
L.Add(new FileDataSource(dir));
|
||||
}
|
||||
FFMpegPath = Path.Combine(bdata, "ffmpeg.exe");
|
||||
|
||||
Audio = new Audio(this, data);
|
||||
|
||||
|
@ -18,20 +18,12 @@ namespace Braver.Field {
|
||||
public int MinX { get; private set; }
|
||||
public int MinY { get; private set; }
|
||||
|
||||
private enum BlendType {
|
||||
Blend,
|
||||
Additive,
|
||||
Subtractive,
|
||||
QuarterAdd,
|
||||
None = 0xff,
|
||||
}
|
||||
|
||||
private class TexLayer {
|
||||
public Texture2D Tex;
|
||||
public VertexPositionTexture[] Verts;
|
||||
public IEnumerable<Ficedula.FF7.Field.Sprite> Sprites;
|
||||
public List<uint[]> Data;
|
||||
public BlendType Blend;
|
||||
public Ficedula.FF7.Field.BlendType Blend;
|
||||
public int Parameter;
|
||||
public int Mask;
|
||||
public int OffsetX, OffsetY;
|
||||
@ -110,7 +102,7 @@ namespace Braver.Field {
|
||||
Tex = new Texture2D(graphics, texWidth, texHeight, false, SurfaceFormat.Color),
|
||||
OffsetX = -minX,
|
||||
OffsetY = -minY,
|
||||
Blend = (BlendType)group.First().TypeTrans,
|
||||
Blend = (Ficedula.FF7.Field.BlendType)group.First().TypeTrans,
|
||||
Sprites = group.ToArray(),
|
||||
Data = Enumerable.Range(0, texHeight)
|
||||
.Select(_ => new uint[texWidth])
|
||||
@ -184,11 +176,11 @@ namespace Braver.Field {
|
||||
continue;
|
||||
|
||||
switch (layer.Blend) {
|
||||
case BlendType.None:
|
||||
case BlendType.Blend:
|
||||
case Ficedula.FF7.Field.BlendType.None:
|
||||
case Ficedula.FF7.Field.BlendType.Blend:
|
||||
_graphics.BlendState = BlendState.AlphaBlend;
|
||||
break;
|
||||
case BlendType.Additive:
|
||||
case Ficedula.FF7.Field.BlendType.Additive:
|
||||
_graphics.BlendState = BlendState.Additive;
|
||||
break;
|
||||
default: //TODO NO
|
||||
|
@ -1,17 +1,29 @@
|
||||
using Ficedula.FF7.Field;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Braver.Field {
|
||||
|
||||
[Flags]
|
||||
public enum BattleFlags {
|
||||
None = 0,
|
||||
TimedBattle = 0x2,
|
||||
Preemptive = 0x4,
|
||||
NoEscape = 0x8,
|
||||
NoVictoryMusic = 0x20,
|
||||
BattleArena = 0x40,
|
||||
NoVictoryScreens = 0x80,
|
||||
NoGameOver = 0x100,
|
||||
}
|
||||
|
||||
public class BattleOptions {
|
||||
public string OverrideMusic { get; set; }
|
||||
public string PostBattleMusic { get; set; } //will play in field
|
||||
public bool BattlesEnabled { get; set; } = false; //TODO - reasonable default?
|
||||
public BattleFlags Flags { get; set; } = BattleFlags.None;
|
||||
}
|
||||
|
||||
public class FieldInfo {
|
||||
public float BGZFrom { get; set; }
|
||||
public float BGZTo { get; set; }
|
||||
@ -38,6 +50,7 @@ namespace Braver.Field {
|
||||
MenuEnabled = 0x4,
|
||||
CameraTracksPlayer = 0x8,
|
||||
CameraIsAsyncScrolling = 0x10,
|
||||
MusicLocked = 0x20,
|
||||
|
||||
DEFAULT = PlayerControls | MenuEnabled | CameraTracksPlayer,
|
||||
}
|
||||
@ -65,14 +78,16 @@ namespace Braver.Field {
|
||||
|
||||
public HashSet<int> DisabledWalkmeshTriangles { get; } = new HashSet<int>();
|
||||
public Background Background { get; private set; }
|
||||
public Movie Movie { get; private set; }
|
||||
public List<Entity> Entities { get; private set; }
|
||||
public Entity Player { get; private set; }
|
||||
public List<FieldModel> FieldModels { get; private set; }
|
||||
public DialogEvent FieldDialog { get; private set; }
|
||||
public FieldOptions Options { get; set; } = FieldOptions.DEFAULT;
|
||||
public Dialog Dialog { get; private set; }
|
||||
public Overlay Overlay { get; private set; }
|
||||
|
||||
public string OverrideBattleMusic { get; set; }
|
||||
public BattleOptions BattleOptions { get; } = new();
|
||||
|
||||
private HashSet<Trigger> _activeTriggers = new();
|
||||
|
||||
@ -89,6 +104,8 @@ namespace Braver.Field {
|
||||
g.Net.Listen<Net.FieldEntityModelMessage>(this);
|
||||
g.Net.Listen<Net.FieldBGScrollMessage>(this);
|
||||
|
||||
Overlay = new Overlay(g, graphics);
|
||||
|
||||
var mapList = g.Singleton(() => new MapList(g.Open("field", "maplist")));
|
||||
string file = mapList.Items[_destination.DestinationFieldID];
|
||||
|
||||
@ -97,6 +114,7 @@ namespace Braver.Field {
|
||||
using (var s = g.Open("field", file)) {
|
||||
var field = new FieldFile(s);
|
||||
Background = new Background(g, graphics, field.GetBackground());
|
||||
Movie = new Movie(g, graphics);
|
||||
FieldDialog = field.GetDialogEvent();
|
||||
|
||||
Entities = FieldDialog.Entities
|
||||
@ -297,7 +315,10 @@ namespace Braver.Field {
|
||||
}
|
||||
|
||||
BringPlayerIntoView();
|
||||
FadeIn(null);
|
||||
|
||||
if (!Overlay.HasTriggered)
|
||||
Overlay.Fade(30, GraphicsUtil.BlendSubtractive, Color.White, Color.Black, null);
|
||||
|
||||
g.Net.Send(new Net.ScreenReadyMessage());
|
||||
}
|
||||
Entity.DEBUG_OUT = false;
|
||||
@ -311,8 +332,12 @@ namespace Braver.Field {
|
||||
protected override void DoRender() {
|
||||
Graphics.DepthStencilState = DepthStencilState.Default;
|
||||
Graphics.BlendState = BlendState.AlphaBlend;
|
||||
if (_renderBG)
|
||||
Background.Render(_view2D, _bgZFrom, _bgZTo);
|
||||
if (_renderBG) {
|
||||
if (Movie.Active)
|
||||
Movie.Render();
|
||||
else
|
||||
Background.Render(_view2D, _bgZFrom, _bgZTo);
|
||||
}
|
||||
|
||||
if (_renderDebug)
|
||||
_debug.Render(_view3D);
|
||||
@ -322,6 +347,8 @@ namespace Braver.Field {
|
||||
if ((entity.Model != null) && entity.Model.Visible)
|
||||
entity.Model.Render(_view3D);
|
||||
|
||||
Overlay.Render();
|
||||
|
||||
Dialog.Render();
|
||||
}
|
||||
|
||||
@ -340,6 +367,7 @@ namespace Braver.Field {
|
||||
protected override void DoStep(GameTime elapsed) {
|
||||
if (Game.Net is Net.Server) {
|
||||
if ((frame % 2) == 0) {
|
||||
Overlay.Step();
|
||||
foreach (var entity in Entities) {
|
||||
entity.Run(1000);
|
||||
entity.Model?.FrameStep();
|
||||
@ -353,6 +381,7 @@ namespace Braver.Field {
|
||||
}
|
||||
|
||||
Dialog.Step();
|
||||
Movie.Step();
|
||||
Background.Step();
|
||||
} else {
|
||||
if ((frame % 2) == 0) {
|
||||
@ -786,6 +815,8 @@ namespace Braver.Field {
|
||||
if (newHeight != null) {
|
||||
//We're staying in the same tri, so just update height
|
||||
eMove.Model.Translation = newPosition.WithZ(newHeight.Value);
|
||||
if (eMove.Name == "ba")
|
||||
System.Diagnostics.Debug.WriteLine($"Moving {eMove.Name} to {eMove.Model.Translation}");
|
||||
return true;
|
||||
} else {
|
||||
if (!DoesLeaveTri(eMove.Model.Translation.XY(), newPosition.XY(), currentTri, out float dist, out short? newTri)) {
|
||||
@ -819,6 +850,8 @@ namespace Braver.Field {
|
||||
}
|
||||
testLocation = testFrom;
|
||||
|
||||
if (eMove.Name == "ba")
|
||||
System.Diagnostics.Debug.WriteLine($"Moving {eMove.Name} from wmtri {eMove.WalkmeshTri} to {newTri.Value}");
|
||||
movingToTri = _walkmesh[newTri.Value];
|
||||
newHeight = HeightInTriangle(
|
||||
movingToTri.V0.ToX(), movingToTri.V1.ToX(), movingToTri.V2.ToX(),
|
||||
@ -828,8 +861,9 @@ namespace Braver.Field {
|
||||
|
||||
eMove.WalkmeshTri = newTri.Value;
|
||||
eMove.Model.Translation = newPosition.WithZ(newHeight.Value);
|
||||
return true;
|
||||
|
||||
if (eMove.Name == "ba")
|
||||
System.Diagnostics.Debug.WriteLine($"Moving {eMove.Name} to {eMove.Model.Translation}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
217
F7/Field/Movie.cs
Normal file
217
F7/Field/Movie.cs
Normal file
@ -0,0 +1,217 @@
|
||||
using Microsoft.Xna.Framework.Audio;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Braver.Field {
|
||||
public class Movie {
|
||||
|
||||
private int _frame;
|
||||
private SpriteBatch _spriteBatch;
|
||||
private GraphicsDevice _graphics;
|
||||
|
||||
public int Frame => _frame;
|
||||
public bool Active => (_process != null) && (_frame >= 0);
|
||||
|
||||
private string _ffPath;
|
||||
|
||||
private Process _process;
|
||||
private Action _onComplete;
|
||||
private SoundEffect _soundEffect;
|
||||
private SoundEffectInstance _effectInstance;
|
||||
private Texture2D _texture;
|
||||
private float _gameFramesPerVideoFrame, _frameIncrement;
|
||||
private byte[] _framebuffer;
|
||||
|
||||
private static Regex _reSize = new Regex(@"(\d+)x(\d+)");
|
||||
|
||||
private string[] _files;
|
||||
|
||||
public Movie(FGame g, GraphicsDevice graphics) {
|
||||
_graphics = graphics;
|
||||
_spriteBatch = new SpriteBatch(graphics);
|
||||
_ffPath = g.FFMpegPath;
|
||||
|
||||
_files = g.OpenString("movies", "movielist.txt")
|
||||
.Split('\n')
|
||||
.Select(s => s.Trim('\r'))
|
||||
.Select(s => Path.Combine(Path.GetDirectoryName(_ffPath), "movies", s + ".mp4")) //TODO!!!
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private unsafe void GetAudioData(string filename, string customCommand) {
|
||||
|
||||
var psi = new ProcessStartInfo {
|
||||
FileName = _ffPath,
|
||||
ArgumentList = {
|
||||
"-i", filename,
|
||||
"-map", "0:a",
|
||||
"-acodec", "pcm_s16le",
|
||||
"-f", "s16le",
|
||||
"-"
|
||||
},
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(customCommand)) {
|
||||
psi.ArgumentList.Clear();
|
||||
psi.Arguments = string.Format(customCommand, filename);
|
||||
}
|
||||
|
||||
_process = Process.Start(psi);
|
||||
|
||||
bool stereo = false;
|
||||
int freq = 0;
|
||||
|
||||
do {
|
||||
string s = _process.StandardError.ReadLine();
|
||||
if (s == null) break;
|
||||
if (s.Contains("Audio: pcm_s16le")) {
|
||||
foreach (string part in s.Split(',')) {
|
||||
if (part.EndsWith("Hz"))
|
||||
freq = int.Parse(part.Substring(0, part.Length - 2).Trim());
|
||||
else if (part.Trim().Equals("stereo", StringComparison.InvariantCultureIgnoreCase))
|
||||
stereo = true;
|
||||
}
|
||||
}
|
||||
} while (freq == 0);
|
||||
|
||||
_process.StandardError.Close();
|
||||
|
||||
if (freq > 0) {
|
||||
var ms = new System.IO.MemoryStream();
|
||||
_process.StandardOutput.BaseStream.CopyTo(ms);
|
||||
byte[] data = ms.ToArray();
|
||||
|
||||
_soundEffect = new SoundEffect(data, freq, stereo ? AudioChannels.Stereo : AudioChannels.Mono);
|
||||
_effectInstance = _soundEffect.CreateInstance();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void Prepare(int movie) {
|
||||
|
||||
string filename = _files[movie];
|
||||
|
||||
GetAudioData(filename, "");
|
||||
|
||||
string ffFormat;
|
||||
int bytesPerPixel;
|
||||
ffFormat = "rgba";
|
||||
bytesPerPixel = 4;
|
||||
|
||||
var psi = new ProcessStartInfo {
|
||||
FileName = _ffPath,
|
||||
ArgumentList = {
|
||||
"-hwaccel", "auto",
|
||||
"-i", filename,
|
||||
"-f", "image2pipe",
|
||||
"-pix_fmt", ffFormat,
|
||||
"-vcodec", "rawvideo",
|
||||
"-blocksize", "65536",
|
||||
"-"
|
||||
},
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
_process = Process.Start(psi);
|
||||
|
||||
int stride;
|
||||
int width = 0, height = 0;
|
||||
float fps = 0;
|
||||
|
||||
do {
|
||||
string s = _process.StandardError.ReadLine();
|
||||
if (s == null) return;
|
||||
if (s.Contains("Video: rawvideo")) {
|
||||
foreach (string part in s.Split(',')) {
|
||||
if (part.EndsWith("fps"))
|
||||
fps = float.Parse(part.Substring(0, part.Length - 3).Trim());
|
||||
var m = _reSize.Match(part.Trim());
|
||||
if (m.Success) {
|
||||
width = int.Parse(m.Groups[1].Value);
|
||||
height = int.Parse(m.Groups[2].Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (width == 0);
|
||||
|
||||
_process.StandardError.Close();
|
||||
if (fps == 0) fps = 30;
|
||||
|
||||
_gameFramesPerVideoFrame = 60 / fps;
|
||||
_frameIncrement = 0;
|
||||
|
||||
stride = width * bytesPerPixel;
|
||||
/* //TODO: Necessary or not?
|
||||
if ((stride % 32) != 0)
|
||||
stride += 32 - (stride % 32);
|
||||
*/
|
||||
|
||||
_texture = new Texture2D(_graphics, stride / bytesPerPixel, height, false, SurfaceFormat.Color);
|
||||
_framebuffer = new byte[_texture.Width * _texture.Height * 4];
|
||||
_texture.SetData(_framebuffer);
|
||||
|
||||
_frame = -1;
|
||||
}
|
||||
|
||||
public void Play(Action onComplete) {
|
||||
_frame = 0;
|
||||
_effectInstance?.Play();
|
||||
_onComplete = onComplete;
|
||||
}
|
||||
|
||||
public void Render() {
|
||||
if (_frame >= 0) {
|
||||
_spriteBatch.Begin(depthStencilState: DepthStencilState.None);
|
||||
|
||||
_spriteBatch.Draw(_texture, new Rectangle(0, 0, _graphics.Viewport.Width, _graphics.Viewport.Height), Color.White);
|
||||
|
||||
_spriteBatch.End();
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Step() {
|
||||
if (_process == null) return;
|
||||
|
||||
_frameIncrement++;
|
||||
|
||||
if (_frameIncrement >= _gameFramesPerVideoFrame) {
|
||||
int read = 0, size = _texture.Width * _texture.Height * 4;
|
||||
fixed (byte* baseptr = &_framebuffer[0]) {
|
||||
while (read < size) {
|
||||
byte* ptr = baseptr + read;
|
||||
int count = _process.StandardOutput.BaseStream.Read(new Span<byte>(ptr, size - read));
|
||||
|
||||
if (count <= 0) {
|
||||
_process.Kill();
|
||||
_process.Dispose();
|
||||
_process = null;
|
||||
_onComplete?.Invoke();
|
||||
break;
|
||||
}
|
||||
|
||||
read += count;
|
||||
}
|
||||
}
|
||||
_texture.SetData(_framebuffer);
|
||||
_frame++;
|
||||
_frameIncrement -= _gameFramesPerVideoFrame;
|
||||
} else {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
56
F7/Field/Overlay.cs
Normal file
56
F7/Field/Overlay.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using Braver.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Braver.Field {
|
||||
public class Overlay {
|
||||
|
||||
private Color _color = Color.Black;
|
||||
private SpriteBatch _spriteBatch;
|
||||
private BlendState _blend;
|
||||
private Texture2D _tex;
|
||||
private Rectangle _rect;
|
||||
|
||||
private Action _onComplete;
|
||||
private int _progress, _duration;
|
||||
private Color _cFrom, _cTo;
|
||||
|
||||
public bool HasTriggered { get; private set; }
|
||||
|
||||
public Overlay(FGame g, GraphicsDevice graphics) {
|
||||
_spriteBatch = new SpriteBatch(graphics);
|
||||
g.Singleton(() => new CompositeImages(graphics, g)).Find("white", out _tex, out _rect, out _);
|
||||
}
|
||||
|
||||
public void Fade(int frames, BlendState blend, Color cFrom, Color cTo, Action onComplete) {
|
||||
_color = _cFrom = cFrom;
|
||||
_cTo = cTo;
|
||||
_onComplete = onComplete;
|
||||
_progress = 0;
|
||||
_duration = frames;
|
||||
_blend = blend;
|
||||
HasTriggered = true;
|
||||
}
|
||||
|
||||
public void Render() {
|
||||
if ((_color.PackedValue & 0xffffff) != 0) {
|
||||
_spriteBatch.Begin(blendState: _blend, depthStencilState: DepthStencilState.None);
|
||||
_spriteBatch.Draw(_tex, new Rectangle(0, 0, 9000, 9000), _rect, _color);
|
||||
_spriteBatch.End();
|
||||
}
|
||||
}
|
||||
|
||||
public void Step() {
|
||||
if (_progress == _duration) {
|
||||
_color = _cTo;
|
||||
_onComplete?.Invoke();
|
||||
} else {
|
||||
_progress++;
|
||||
_color = Color.Lerp(_cFrom, _cTo, 1f * _progress / _duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
195
F7/Field/VM.cs
195
F7/Field/VM.cs
@ -1,15 +1,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using NAudio.Gui;
|
||||
using SharpDX.Direct2D1;
|
||||
using SharpDX.Direct3D9;
|
||||
using SixLabors.ImageSharp;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
||||
|
||||
namespace Braver.Field {
|
||||
public enum OpCode {
|
||||
@ -383,6 +375,7 @@ namespace Braver.Field {
|
||||
Register(typeof(PartyInventory));
|
||||
Register(typeof(FieldModels));
|
||||
Register(typeof(Maths));
|
||||
Register(typeof(SystemControl));
|
||||
}
|
||||
|
||||
public static OpResult Execute(OpCode op, Fiber f, Entity e, FieldScreen s) {
|
||||
@ -783,6 +776,17 @@ namespace Braver.Field {
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
public static OpResult CANIM2(Fiber f, Entity e, FieldScreen s) {
|
||||
byte anim = f.ReadU8(), first = f.ReadU8(), last = f.ReadU8(), speed = f.ReadU8();
|
||||
f.Pause();
|
||||
var state = e.Model.AnimationState;
|
||||
Action onComplete = () => {
|
||||
f.Resume();
|
||||
e.Model.AnimationState = state;
|
||||
};
|
||||
e.Model.PlayAnimation(anim, false, 1f / speed, onComplete, first, last); //TODO is this speed even vaguely correct?
|
||||
return OpResult.Continue;
|
||||
}
|
||||
public static OpResult ANIME1(Fiber f, Entity e, FieldScreen s) {
|
||||
byte anim = f.ReadU8(), speed = f.ReadU8();
|
||||
f.Pause();
|
||||
@ -937,6 +941,11 @@ namespace Braver.Field {
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
public static OpResult MMBLK(Fiber f, Entity e, FieldScreen s) {
|
||||
byte charID = f.ReadU8();
|
||||
s.Game.SaveData.Characters[charID].Flags |= CharFlags.Locked;
|
||||
return OpResult.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class WindowMenu {
|
||||
@ -1051,14 +1060,76 @@ if (y + h + MIN_WINDOW_DISTANCE > GAME_HEIGHT) { y = GAME_HEIGHT - h - MIN_WINDO
|
||||
|
||||
public static OpResult MUSIC(Fiber f, Entity e, FieldScreen s) {
|
||||
byte track = f.ReadU8();
|
||||
s.Game.Audio.PlayMusic(_trackNames[s.FieldDialog.AkaoMusicIDs[track]]);
|
||||
if (!s.Options.HasFlag(FieldOptions.MusicLocked))
|
||||
s.Game.Audio.PlayMusic(_trackNames[s.FieldDialog.AkaoMusicIDs[track]]);
|
||||
return OpResult.Continue;
|
||||
}
|
||||
public static OpResult BMUSC(Fiber f, Entity e, FieldScreen s) {
|
||||
byte track = f.ReadU8();
|
||||
s.OverrideBattleMusic = _trackNames[s.FieldDialog.AkaoMusicIDs[track]];
|
||||
s.BattleOptions.OverrideMusic = _trackNames[s.FieldDialog.AkaoMusicIDs[track]];
|
||||
return OpResult.Continue;
|
||||
}
|
||||
public static OpResult FMUSC(Fiber f, Entity e, FieldScreen s) {
|
||||
byte track = f.ReadU8();
|
||||
s.BattleOptions.PostBattleMusic = _trackNames[s.FieldDialog.AkaoMusicIDs[track]];
|
||||
return OpResult.Continue;
|
||||
}
|
||||
public static OpResult MULCK(Fiber f, Entity e, FieldScreen s) {
|
||||
byte locked = f.ReadU8();
|
||||
if (locked != 0)
|
||||
s.Options |= FieldOptions.MusicLocked;
|
||||
else
|
||||
s.Options &= ~FieldOptions.MusicLocked;
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
private static OpResult DoAKAO(Fiber f, Entity e, FieldScreen s, byte op, int parm1, int parm2, int parm3, int parm4, int parm5) {
|
||||
switch (op) {
|
||||
case 0xc8:
|
||||
case 0xc9:
|
||||
case 0xca:
|
||||
//Music pan - Not implemented in original FF7 (but maybe we could?)
|
||||
break;
|
||||
|
||||
case 0xf0:
|
||||
if (!s.Options.HasFlag(FieldOptions.MusicLocked))
|
||||
s.Game.Audio.StopMusic();
|
||||
break;
|
||||
|
||||
default: //TODO - all ops!
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
public static OpResult AKAO(Fiber f, Entity e, FieldScreen s) {
|
||||
byte bank12 = f.ReadU8(), bank34 = f.ReadU8(), bank5 = f.ReadU8(),
|
||||
op = f.ReadU8(), p1 = f.ReadU8();
|
||||
ushort p2 = f.ReadU16(), p3 = f.ReadU16(), p4 = f.ReadU16(), p5 = f.ReadU16();
|
||||
|
||||
int parm1 = s.Game.Memory.Read(bank12 >> 4, p1),
|
||||
parm2 = s.Game.Memory.Read(bank12 & 0xf, p2),
|
||||
parm3 = s.Game.Memory.Read(bank34 >> 4, p3),
|
||||
parm4 = s.Game.Memory.Read(bank34 & 0xf, p4),
|
||||
parm5 = s.Game.Memory.Read(bank5 >> 4, p5);
|
||||
|
||||
return DoAKAO(f, e, s, op, parm1, parm2, parm3, parm4, parm5);
|
||||
}
|
||||
public static OpResult AKAO2(Fiber f, Entity e, FieldScreen s) {
|
||||
byte bank12 = f.ReadU8(), bank34 = f.ReadU8(), bank5 = f.ReadU8(),
|
||||
op = f.ReadU8();
|
||||
ushort p1 = f.ReadU16(), p2 = f.ReadU16(), p3 = f.ReadU16(), p4 = f.ReadU16(), p5 = f.ReadU16();
|
||||
|
||||
int parm1 = s.Game.Memory.Read(bank12 >> 4, p1),
|
||||
parm2 = s.Game.Memory.Read(bank12 & 0xf, p2),
|
||||
parm3 = s.Game.Memory.Read(bank34 >> 4, p3),
|
||||
parm4 = s.Game.Memory.Read(bank34 & 0xf, p4),
|
||||
parm5 = s.Game.Memory.Read(bank5 >> 4, p5);
|
||||
|
||||
return DoAKAO(f, e, s, op, parm1, parm2, parm3, parm4, parm5);
|
||||
}
|
||||
|
||||
|
||||
public static OpResult SOUND(Fiber f, Entity e, FieldScreen s) {
|
||||
byte banks = f.ReadU8();
|
||||
@ -1070,6 +1141,23 @@ if (y + h + MIN_WINDOW_DISTANCE > GAME_HEIGHT) { y = GAME_HEIGHT - h - MIN_WINDO
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
public static OpResult PMVIE(Fiber f, Entity e, FieldScreen s) {
|
||||
byte which = f.ReadU8();
|
||||
s.Movie.Prepare(which);
|
||||
return OpResult.Continue;
|
||||
}
|
||||
public static OpResult MOVIE(Fiber f, Entity e, FieldScreen s) {
|
||||
f.Pause();
|
||||
s.Movie.Play(f.Resume);
|
||||
return OpResult.Continue;
|
||||
}
|
||||
public static OpResult MVIEF(Fiber f, Entity e, FieldScreen s) {
|
||||
byte bank = f.ReadU8(), addr = f.ReadU8();
|
||||
s.Game.Memory.Write(bank, addr, (ushort)Math.Max(0, s.Movie.Frame));
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
|
||||
public static OpResult SCRLW(Fiber f, Entity e, FieldScreen s) {
|
||||
if (s.Options.HasFlag(FieldOptions.CameraIsAsyncScrolling))
|
||||
return OpResult.Restart;
|
||||
@ -1087,6 +1175,41 @@ if (y + h + MIN_WINDOW_DISTANCE > GAME_HEIGHT) { y = GAME_HEIGHT - h - MIN_WINDO
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
private class ScrollState {
|
||||
public Vector2 Start;
|
||||
public int Frame;
|
||||
}
|
||||
public static OpResult SCR2DC(Fiber f, Entity e, FieldScreen s) {
|
||||
byte banks = f.ReadU8(), bankS = f.ReadU8();
|
||||
short sx = f.ReadS16(), sy = f.ReadS16(), ss = f.ReadS16();
|
||||
int x = s.Game.Memory.Read(banks & 0xf, sx),
|
||||
y = s.Game.Memory.Read(banks >> 4, sy),
|
||||
speed = s.Game.Memory.Read(bankS, ss);
|
||||
|
||||
ScrollState state;
|
||||
if (f.ResumeState == null) {
|
||||
var scroll = s.GetBGScroll();
|
||||
state = new ScrollState {
|
||||
Start = new Vector2(scroll.x, scroll.y),
|
||||
};
|
||||
f.ResumeState = state;
|
||||
} else
|
||||
state = (ScrollState)f.ResumeState;
|
||||
|
||||
Vector2 end = new Vector2(x, y);
|
||||
var progress = Easings.QuadraticInOut(1f * state.Frame / speed); //TODO - is interpreting speed as framecount vaguely correct?
|
||||
|
||||
if (progress >= 1f) {
|
||||
s.BGScroll(x, y);
|
||||
return OpResult.Continue;
|
||||
} else {
|
||||
var pos = state.Start + (end - state.Start) * progress;
|
||||
s.BGScroll(pos.X, pos.Y);
|
||||
state.Frame++;
|
||||
return OpResult.Restart;
|
||||
}
|
||||
}
|
||||
|
||||
public static OpResult SCRLC(Fiber f, Entity e, FieldScreen s) {
|
||||
byte bank = f.ReadU8();
|
||||
byte sspeed = f.ReadU8();
|
||||
@ -1157,6 +1280,42 @@ if (y + h + MIN_WINDOW_DISTANCE > GAME_HEIGHT) { y = GAME_HEIGHT - h - MIN_WINDO
|
||||
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
private static OpResult DoFade(Fiber f, Entity e, FieldScreen s, byte bankRG, byte bankB,
|
||||
byte r, byte g, byte b, byte frames, byte fadeType, byte adjust) {
|
||||
|
||||
int cR = (byte)s.Game.Memory.Read(bankRG >> 4, r),
|
||||
cG = (byte)s.Game.Memory.Read(bankRG & 0xf, g),
|
||||
cB = (byte)s.Game.Memory.Read(bankB, b);
|
||||
|
||||
Color cStandard = new Color(cR, cG, cB, 0xff),
|
||||
cInverse = new Color(0xff - cR, 0xff - cG, 0xff - cB, 0xff),
|
||||
cInverse4 = new Color(4 * (0xff - cR), 4 * (0xff - cG), 4 * (0xff - cB), 0xff);
|
||||
|
||||
switch (fadeType) {
|
||||
case 0: //NFADE type 0
|
||||
case 4: //FADE type 4 - both basically the same...?
|
||||
s.Overlay.Fade(0, BlendState.Additive, Color.Black, Color.Black, null);
|
||||
return OpResult.Continue;
|
||||
default: //TODO - other types!
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static OpResult NFADE(Fiber f, Entity e, FieldScreen s) {
|
||||
byte bankRG = f.ReadU8(), bankB = f.ReadU8(), fadeType = f.ReadU8(),
|
||||
r = f.ReadU8(), g = f.ReadU8(), b = f.ReadU8(),
|
||||
speed = f.ReadU8(), adjust = f.ReadU8();
|
||||
|
||||
return DoFade(f, e, s, bankRG, bankB, r, g, b, speed, fadeType, adjust);
|
||||
}
|
||||
public static OpResult FADE(Fiber f, Entity e, FieldScreen s) {
|
||||
byte bankRG = f.ReadU8(), bankB = f.ReadU8(), r = f.ReadU8(), g = f.ReadU8(), b = f.ReadU8(),
|
||||
speed = f.ReadU8(), fadeType = f.ReadU8(), adjust = f.ReadU8();
|
||||
|
||||
return DoFade(f, e, s, bankRG, bankB, r, g, b, (byte)(240 / speed), fadeType, adjust);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal static class Maths {
|
||||
@ -1214,4 +1373,16 @@ if (y + h + MIN_WINDOW_DISTANCE > GAME_HEIGHT) { y = GAME_HEIGHT - h - MIN_WINDO
|
||||
return OpResult.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SystemControl {
|
||||
public static OpResult BTLON(Fiber f, Entity e, FieldScreen s) {
|
||||
s.BattleOptions.BattlesEnabled = f.ReadU8() == 0;
|
||||
return OpResult.Continue;
|
||||
}
|
||||
|
||||
public static OpResult BTLMD(Fiber f, Entity e, FieldScreen s) {
|
||||
s.BattleOptions.Flags = (BattleFlags)f.ReadU16();
|
||||
return OpResult.Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,23 @@ namespace Braver {
|
||||
|
||||
public static class GraphicsUtil {
|
||||
|
||||
public static readonly BlendState BlendSubtractive = new BlendState {
|
||||
AlphaBlendFunction = BlendFunction.ReverseSubtract,
|
||||
AlphaDestinationBlend = Blend.One,
|
||||
AlphaSourceBlend = Blend.SourceAlpha,
|
||||
ColorBlendFunction = BlendFunction.ReverseSubtract,
|
||||
ColorDestinationBlend = Blend.One,
|
||||
ColorSourceBlend = Blend.SourceAlpha,
|
||||
};
|
||||
public static readonly BlendState BlendDarken = new BlendState {
|
||||
AlphaBlendFunction = BlendFunction.ReverseSubtract,
|
||||
AlphaDestinationBlend = Blend.One,
|
||||
AlphaSourceBlend = Blend.One,
|
||||
ColorBlendFunction = BlendFunction.ReverseSubtract,
|
||||
ColorDestinationBlend = Blend.One,
|
||||
ColorSourceBlend = Blend.InverseSourceColor,
|
||||
};
|
||||
|
||||
public static int MakePowerOfTwo(int i) {
|
||||
int n = 1;
|
||||
while (n < i)
|
||||
|
10
F7/TODO.txt
10
F7/TODO.txt
@ -6,17 +6,17 @@
|
||||
Background load razor engine - do other templates? Automatically load all of them after any specified
|
||||
"priority" templates like MainMenu?
|
||||
|
||||
Moving through walkmap triangles on field is still broken, esp. when running
|
||||
|
||||
IFKEYON etc not fully working - prob. due to IsJustPressed one-frame check conflicting with field scripts
|
||||
not running every frame?
|
||||
|
||||
Shops!
|
||||
|
||||
ASK opcode
|
||||
|
||||
Compressed/single file saves
|
||||
|
||||
Music looping
|
||||
|
||||
Item menu: Icons, actually do arrange
|
||||
Item menu: Icons, actually do arrange
|
||||
|
||||
Field Fade network msg, movie msg
|
||||
|
||||
NEED TO IMPLEMENT field walkmesh tri sliding for first map to complete!
|
@ -59,11 +59,17 @@ namespace Braver.UI {
|
||||
Game.NewGame();
|
||||
Game.ChangeScreen(this, new Field.FieldScreen(
|
||||
new Ficedula.FF7.Field.FieldDestination {
|
||||
X = 7, Y = -107, Triangle = 21,
|
||||
X = 3600, Y = 27320, Triangle = 28,
|
||||
Orientation = 132,
|
||||
DestinationFieldID = 180,
|
||||
DestinationFieldID = 116,
|
||||
}
|
||||
|
||||
/*
|
||||
new Ficedula.FF7.Field.FieldDestination {
|
||||
X = 7, Y = -107, Triangle = 21,
|
||||
Orientation = 132,
|
||||
DestinationFieldID = 180,
|
||||
}
|
||||
*/
|
||||
/*
|
||||
new Ficedula.FF7.Field.FieldDestination {
|
||||
X = -225, Y = -830, Triangle = 152,
|
||||
|
54
data/movies/movielist.txt
Normal file
54
data/movies/movielist.txt
Normal file
@ -0,0 +1,54 @@
|
||||
fship2
|
||||
|
||||
d_ropego
|
||||
d_ropein
|
||||
u_ropein
|
||||
u_ropego
|
||||
gold2
|
||||
gold3
|
||||
gold4
|
||||
gold6
|
||||
gold5
|
||||
boogup
|
||||
boogdown
|
||||
junair_u
|
||||
junair_d
|
||||
junelein
|
||||
junelego
|
||||
junin_in
|
||||
junin_go
|
||||
moriya
|
||||
mkup
|
||||
northmk
|
||||
mk8
|
||||
ontrain
|
||||
mainplr
|
||||
smk
|
||||
southmk
|
||||
plrexp
|
||||
fallpl
|
||||
monitor
|
||||
bike
|
||||
mtnvl
|
||||
mtnvl2
|
||||
brgnvl
|
||||
nvlmk
|
||||
nivlsfs
|
||||
jenova_e
|
||||
junon
|
||||
hiwind0
|
||||
mtcrl
|
||||
gold1
|
||||
biskdead
|
||||
boogdemo
|
||||
boogstar
|
||||
setogake
|
||||
rcktfail
|
||||
jairofly
|
||||
jairofal
|
||||
gold7
|
||||
gold7_2
|
||||
earithdd
|
||||
funeral
|
||||
car_1209
|
||||
opening
|
Loading…
Reference in New Issue
Block a user