mirror of
https://github.com/ficed/Braver.git
synced 2025-02-22 05:10:39 +00:00
Expand dialog plugins to provide more info on each individual line
Support voiced dialog in FFNx compat plugin Support TryLoad on audio streams Fix MENU opcode returning too quickly Implement SPECIAL 0xFD sub-op Make unrecognised text characters a warning in renderer rather than an error Add a few more characters to font Recognise avatar tag characters in text decoder (don't do anything with them yet) More 7H support - map folders properly
This commit is contained in:
parent
e1a43931e8
commit
449c1b837e
@ -46,6 +46,7 @@ namespace Braver {
|
||||
void PlaySfx(Sfx which, float volume, float pan, int? channel = null);
|
||||
|
||||
IAudioItem LoadStream(string path, string file);
|
||||
IAudioItem TryLoadStream(string path, string file);
|
||||
void DecodeStream(Stream s, out byte[] rawData, out int channels, out int frequency);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace Braver.Plugins.Field {
|
||||
public interface IDialog : IPluginInstance {
|
||||
void Showing(int window, int tag, IEnumerable<string> text);
|
||||
void Asking(int window, int tag, IEnumerable<string> text, IEnumerable<int> choiceLines);
|
||||
void Dialog(string dialog);
|
||||
void Dialog(int tag, int index, string dialog);
|
||||
void ChoiceSelected(IEnumerable<string> choices, int selected);
|
||||
void ChoiceMade(int window, int choice);
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrackBar;
|
||||
|
||||
namespace Braver {
|
||||
|
||||
@ -444,8 +443,17 @@ namespace Braver {
|
||||
}
|
||||
|
||||
public IAudioItem LoadStream(string path, string file) {
|
||||
var item = TryLoadStream(path, file);
|
||||
if (item == null) throw new InvalidDataException($"Could not find audio stream {path}/{file}");
|
||||
return item;
|
||||
}
|
||||
public IAudioItem TryLoadStream(string path, string file) {
|
||||
//TODO networking
|
||||
return new LoadedAudioItem(_game.Open(path, file));
|
||||
var s = _game.TryOpen(path, file);
|
||||
if (s != null)
|
||||
return new LoadedAudioItem(s);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public void DecodeStream(Stream s, out byte[] rawData, out int channels, out int frequency) {
|
||||
|
@ -47,7 +47,7 @@ namespace Braver.Field {
|
||||
public int X, Y, Width, Height;
|
||||
public string[] Text;
|
||||
public WindowState State = WindowState.Hidden;
|
||||
public int FrameProgress, ScreenProgress;
|
||||
public int FrameProgress, ScreenProgress, Tag;
|
||||
public Action OnClosed;
|
||||
public Action<int?> OnChoice;
|
||||
public int Choice;
|
||||
@ -61,7 +61,7 @@ namespace Braver.Field {
|
||||
public bool ReadyForChoice => (ChoiceLines != null) && (ScreenProgress == (Text.Length - 1));
|
||||
|
||||
public void StateChanged(PluginInstances<IDialog> plugins) {
|
||||
plugins.Call(ui => ui.Dialog(Text[ScreenProgress]));
|
||||
plugins.Call(ui => ui.Dialog(Tag, ScreenProgress, Text[ScreenProgress]));
|
||||
if (ReadyForChoice)
|
||||
ChoiceChanged(plugins);
|
||||
}
|
||||
@ -118,7 +118,7 @@ namespace Braver.Field {
|
||||
_windows[window].VariableY = y;
|
||||
}
|
||||
|
||||
private void PrepareWindow(int window, string text) {
|
||||
private void PrepareWindow(int window, string text, int tag) {
|
||||
var chars = _game.SaveData.Characters.Select(c => c?.Name).ToArray();
|
||||
var party = _game.SaveData.Party.Select(c => c?.Name).ToArray();
|
||||
var win = _windows[window];
|
||||
@ -126,6 +126,7 @@ namespace Braver.Field {
|
||||
.Select(line => Ficedula.FF7.Text.Expand(line, chars, party))
|
||||
.ToArray();
|
||||
win.FrameProgress = win.ScreenProgress = win.LineScroll = 0;
|
||||
win.Tag = tag;
|
||||
|
||||
win.StateChanged(_plugins);
|
||||
|
||||
@ -149,14 +150,14 @@ namespace Braver.Field {
|
||||
}
|
||||
|
||||
public void Show(int window, int tag, string text, Action onClosed) {
|
||||
PrepareWindow(window, text);
|
||||
PrepareWindow(window, text, tag);
|
||||
_windows[window].OnClosed = onClosed;
|
||||
_windows[window].OnChoice = null;
|
||||
_windows[window].ChoiceLines = null;
|
||||
_plugins.Call(dlg => dlg.Showing(window, tag, _windows[window].Text));
|
||||
}
|
||||
public void Ask(int window, int tag, string text, IEnumerable<int> choices, Action<int?> onChoice) {
|
||||
PrepareWindow(window, text);
|
||||
PrepareWindow(window, text, tag);
|
||||
_windows[window].ChoiceLines = choices.ToArray();
|
||||
_windows[window].OnClosed = null;
|
||||
_windows[window].OnChoice = onChoice;
|
||||
|
@ -1802,18 +1802,18 @@ if (y + h + MIN_WINDOW_DISTANCE > GAME_HEIGHT) { y = GAME_HEIGHT - h - MIN_WINDO
|
||||
s.Game.PushScreen(new UI.Layout.LayoutScreen("Name", parm: parmValue));
|
||||
else
|
||||
throw new NotImplementedException();
|
||||
break;
|
||||
return OpResult.ContinueNextFrame;
|
||||
|
||||
case 0x8:
|
||||
s.Game.PushScreen(new UI.Layout.LayoutScreen("Shop", parm: parmValue));
|
||||
break;
|
||||
return OpResult.ContinueNextFrame;
|
||||
|
||||
case 0x9:
|
||||
s.Game.PushScreen(new UI.Layout.LayoutScreen("MainMenu"));
|
||||
break;
|
||||
return OpResult.ContinueNextFrame;
|
||||
case 0xE:
|
||||
s.Game.PushScreen(new UI.Layout.LayoutScreen("SaveMenu"));
|
||||
break;
|
||||
return OpResult.ContinueNextFrame;
|
||||
|
||||
case 0x12: //Save materia - saving main stock & party member 0, since that seems like the intended use...
|
||||
var saved = s.Game.Singleton(() => new SavedMateria());
|
||||
@ -2473,6 +2473,11 @@ if (y + h + MIN_WINDOW_DISTANCE > GAME_HEIGHT) { y = GAME_HEIGHT - h - MIN_WINDO
|
||||
s.Options |= FieldOptions.ShowPlayerHand;
|
||||
break;
|
||||
|
||||
case 0xFD:
|
||||
byte chr = f.ReadU8(), text = f.ReadU8();
|
||||
s.Game.SaveData.Characters[chr].Name = s.FieldDialog.Dialogs[text];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"SPECIAL op {subOp:x2} not implemented");
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@ -404,6 +405,10 @@ namespace Braver.UI {
|
||||
Color colour = item.colour;
|
||||
foreach (char c in item.text) {
|
||||
switch (c) {
|
||||
case '¬':
|
||||
Trace.TraceWarning($"Unrecognised char in string '{item.text}'");
|
||||
break;
|
||||
|
||||
case '\xE012':
|
||||
//Colour change opcode ... ignore and just pay attention to the actual colour code
|
||||
break;
|
||||
@ -422,6 +427,18 @@ namespace Braver.UI {
|
||||
case '\xE030': //pause opcode - just skip
|
||||
break;
|
||||
|
||||
case '\xE040': //avatar opcodes - just skip
|
||||
case '\xE041':
|
||||
case '\xE042':
|
||||
case '\xE043':
|
||||
case '\xE044':
|
||||
case '\xE045':
|
||||
case '\xE046':
|
||||
case '\xE047':
|
||||
case '\xE048':
|
||||
case '\xE049':
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
dx += (int)(f.GlyphsDict['i'].W * 1 * item.Size);
|
||||
break;
|
||||
|
@ -8,6 +8,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ficedula.FF7 {
|
||||
@ -17,20 +18,33 @@ namespace Ficedula.FF7 {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
||||
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
|
||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', //0x40
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', ' ', '}', '~', ' ',
|
||||
'¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '…', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '“', '”', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '\xE040', '\xE041', '¬', '\xE042', '\xE043', '¬', '\xE044', //0x80
|
||||
'¬', '\xE045', '\xE046', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '¬', '\xE047', '\xE048', '\xE049', '¬', '¬', '¬', '…', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '—', '“', '”', '¬', '’', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬',
|
||||
'¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', //0xC0
|
||||
' ', '¬', '\xE020', '\xE021', '\xE022', '\xE023', '\xE024', '\xE025', '\xE026', '\xE027', '\xE028', '\xE029', '\xE030', '¬', '¬', '¬',
|
||||
'\xE000', '\t', '\xE003', '\xE001', '\xE002', '¬', '¬', '\r', '\xC', '\xE005', '\xE006', '\xE007', '\xE008', '\xE009', '\xE00A', '\xE00B',
|
||||
'\xE00C', '\xE00D', '\xE00E', '\xE00F', '\xE010', '\xE011', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '¬', '\xE012', '\xE013',
|
||||
};
|
||||
|
||||
/*
|
||||
8D 141 Cloud E043
|
||||
89 137 Barret E040
|
||||
A4 164 Tifa E048
|
||||
8F 143 Aeris E044
|
||||
A3 163 Red? E047
|
||||
92 146 Sephiroth? E046
|
||||
91 145 Cait Sith E045
|
||||
A5 165 Yuffie E049
|
||||
8C 140 Cid E042
|
||||
8A 138 Vincent E041
|
||||
*/
|
||||
|
||||
public static string Convert(byte[] input, int offset, int? length = null) {
|
||||
char[] c = Enumerable.Range(offset, length ?? input.Length - offset)
|
||||
.Select(i => _translate[input[i]])
|
||||
|
@ -217,7 +217,14 @@ namespace Braver._7HShim {
|
||||
return _iro.AllFolderNames()
|
||||
.Where(s => s.StartsWith(prefix))
|
||||
.Select(s => s.Substring(prefix.Length))
|
||||
.Where(s => !s.Contains('\\'));
|
||||
.Select(s => {
|
||||
int separator = s.IndexOf('\\');
|
||||
if (separator >= 0)
|
||||
return s.Substring(0, separator);
|
||||
else
|
||||
return s;
|
||||
})
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
@ -366,6 +373,19 @@ namespace Braver._7HShim {
|
||||
yield break;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> _folderRemap = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) {
|
||||
["char.lgp"] = "field",
|
||||
["flevel.lgp"] = "field",
|
||||
};
|
||||
|
||||
private string RemapSourceName(string name) {
|
||||
name = Path.GetFileName(name);
|
||||
if (_folderRemap.TryGetValue(name, out string remap))
|
||||
return remap;
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
public override void Init(BGame game) {
|
||||
foreach(var mod in _mods) {
|
||||
HashSet<string> remainingFolders = new HashSet<string>(mod.GetFolders(), StringComparer.InvariantCultureIgnoreCase);
|
||||
@ -381,11 +401,11 @@ namespace Braver._7HShim {
|
||||
isActive = true;
|
||||
if (isActive) {
|
||||
foreach (string datafolder in mod.GetSubFolders(folder))
|
||||
game.AddDataSource(Path.GetFileName(datafolder), mod.GetDataSource(folder, datafolder));
|
||||
game.AddDataSource(RemapSourceName(datafolder), mod.GetDataSource(folder, datafolder));
|
||||
}
|
||||
}
|
||||
foreach (string folder in remainingFolders)
|
||||
game.AddDataSource(Path.GetFileName(folder), mod.GetDataSource(folder, ""));
|
||||
game.AddDataSource(RemapSourceName(folder), mod.GetDataSource(folder, ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ namespace Braver.FFNxCompatibility {
|
||||
public bool FieldAmbientSounds { get; set; } = true;
|
||||
[ConfigProperty("Allow replacing sound effects")]
|
||||
public bool ReplaceSfx { get; set; } = true;
|
||||
[ConfigProperty("Allow voicing field dialog")]
|
||||
public bool FieldDialogVoices { get; set; } = true;
|
||||
}
|
||||
|
||||
public class FFNxPlugin : Plugin {
|
||||
@ -45,6 +47,9 @@ namespace Braver.FFNxCompatibility {
|
||||
_sfx ??= GetToml("Sfx");
|
||||
yield return new FFNxSfx(_game, _sfx);
|
||||
}
|
||||
if (t == typeof(IDialog)) {
|
||||
yield return new FFNxFieldVoices(_game, context);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<Type> GetPluginInstances() {
|
||||
@ -52,6 +57,8 @@ namespace Braver.FFNxCompatibility {
|
||||
yield return typeof(IFieldLocation);
|
||||
if (_config.ReplaceSfx)
|
||||
yield return typeof(ISfxSource);
|
||||
if (_config.FieldDialogVoices)
|
||||
yield return typeof(IDialog);
|
||||
}
|
||||
|
||||
public override void Init(BGame game) {
|
||||
@ -117,6 +124,49 @@ namespace Braver.FFNxCompatibility {
|
||||
}
|
||||
}
|
||||
|
||||
public class FFNxFieldVoices : IDialog, IDisposable {
|
||||
|
||||
private IAudioItem _playing;
|
||||
private BGame _game;
|
||||
private string _field;
|
||||
|
||||
public FFNxFieldVoices(BGame game, string field) {
|
||||
_game = game;
|
||||
_field = field;
|
||||
}
|
||||
|
||||
public void Asking(int window, int tag, IEnumerable<string> text, IEnumerable<int> choiceLines) {
|
||||
//
|
||||
}
|
||||
|
||||
public void ChoiceMade(int window, int choice) {
|
||||
//
|
||||
}
|
||||
|
||||
public void ChoiceSelected(IEnumerable<string> choices, int selected) {
|
||||
//
|
||||
}
|
||||
|
||||
public void Dialog(int tag, int index, string dialog) {
|
||||
if (_playing != null) {
|
||||
_playing.Stop();
|
||||
_playing.Dispose();
|
||||
_playing = null;
|
||||
}
|
||||
_playing = _game.Audio.TryLoadStream("Voice", $"{_field}\\{tag}.ogg")
|
||||
?? _game.Audio.TryLoadStream("Voice", $"{_field}\\{tag}{(char)('a' + index)}.ogg");
|
||||
_playing?.Play(1f, 0f, false, 1f);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
_playing?.Dispose();
|
||||
}
|
||||
|
||||
public void Showing(int window, int tag, IEnumerable<string> text) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
public class FFNxFieldAmbience : FFNxAudioPlugin, IFieldLocation, IDisposable {
|
||||
private List<TomlTable> _ambients;
|
||||
private IAudioItem _audio;
|
||||
|
@ -22,6 +22,8 @@ namespace Braver.Tolk {
|
||||
public bool EnableFootsteps { get; set; } = true;
|
||||
[ConfigProperty("Enable Focus sounds")]
|
||||
public bool EnableFocusTracking { get; set; } = true;
|
||||
[ConfigProperty("Voice dialogue")]
|
||||
public bool VoiceDialogue { get; set; } = true;
|
||||
}
|
||||
|
||||
public class TolkPlugin : Plugin {
|
||||
@ -59,9 +61,12 @@ namespace Braver.Tolk {
|
||||
|
||||
public class TolkInstance : ISystem, IDialog, IUI, IBattleUI {
|
||||
|
||||
private bool _dialog;
|
||||
|
||||
public TolkInstance(TolkConfig config) {
|
||||
DavyKager.Tolk.TrySAPI(config.EnableSAPI);
|
||||
DavyKager.Tolk.Load();
|
||||
_dialog = config.VoiceDialogue;
|
||||
}
|
||||
|
||||
public void ActiveScreenChanged(IScreen screen) {
|
||||
@ -75,8 +80,9 @@ namespace Braver.Tolk {
|
||||
);
|
||||
}
|
||||
|
||||
public void Dialog(string dialog) {
|
||||
DavyKager.Tolk.Speak(dialog, false);
|
||||
public void Dialog(int tag, int index, string dialog) {
|
||||
if (_dialog)
|
||||
DavyKager.Tolk.Speak(dialog, false);
|
||||
}
|
||||
|
||||
private object _lastMenuContainer = null;
|
||||
|
@ -66,6 +66,7 @@
|
||||
<Glyph X="224" Y="120" W="10" H="24" Layer="0">249</Glyph>
|
||||
<Glyph X="8" Y="144" W="13" H="24" Layer="0">169</Glyph>
|
||||
<Glyph X="8" Y="192" W="8" H="24" Layer="0">8221</Glyph>
|
||||
<Glyph X="56" Y="144" W="5" H="24" Layer="0">8217</Glyph>
|
||||
<Glyph X="24" Y="0" W="3" H="24" Layer="1">33</Glyph>
|
||||
<Glyph X="48" Y="0" W="7" H="24" Layer="1">34</Glyph>
|
||||
<Glyph X="72" Y="0" W="16" H="24" Layer="1">35</Glyph>
|
||||
@ -122,6 +123,7 @@
|
||||
<Glyph X="240" Y="96" W="12" H="24" Layer="1">126</Glyph>
|
||||
<Glyph X="240" Y="192" W="8" H="24" Layer="1">8220</Glyph>
|
||||
<Glyph X="24" Y="192" W="24" H="24" Layer="1">8230</Glyph>
|
||||
<Glyph X="216" Y="192" W="18" H="24" Layer="1">8212</Glyph>
|
||||
</Glyphs>
|
||||
</FontSet>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user