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:
ficedula 2023-01-17 23:37:38 +00:00
parent a35d7dab14
commit 11293aa771
12 changed files with 597 additions and 46 deletions

View File

@ -56,6 +56,7 @@ namespace Braver {
Party3 = 0x40,
Available = 0x100,
Locked = 0x200,
ANY_PARTY_SLOT = Party1 | Party2 | Party3,
}

View File

@ -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" />

View File

@ -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);

View File

@ -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

View File

@ -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
View 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
View 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);
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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)

View File

@ -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!

View File

@ -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
View 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