Skip to content

Commit

Permalink
Add event table support (#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonko0493 authored Jul 22, 2024
1 parent 2c9c9f3 commit bb6e2a3
Show file tree
Hide file tree
Showing 8 changed files with 381 additions and 72 deletions.
18 changes: 13 additions & 5 deletions src/SerialLoops.Lib/Flags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace SerialLoops.Lib
{
public class Flags
{
public const int NUM_FLAGS = 5120;
public static readonly Dictionary<int, string> _names = JsonSerializer.Deserialize<Dictionary<int, string>>(File.ReadAllText(Extensions.GetLocalizedFilePath(Path.Combine("Defaults", "DefaultFlags"), "json")));

public static string GetFlagNickname(int flag, Project project)
Expand All @@ -22,35 +23,42 @@ public static string GetFlagNickname(int flag, Project project)
TopicItem topic = (TopicItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Topic && ((TopicItem)i).TopicEntry.Id == flag);
if (topic is not null)
{
return $"{topic.DisplayName} Obtained";
return string.Format(project.Localize("{0} Obtained"), topic.DisplayName);
}

TopicItem readTopic = (TopicItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Topic &&
((((TopicItem)i).TopicEntry.Type == TopicType.Main && ((TopicItem)i).HiddenMainTopic is not null && ((TopicItem)i).TopicEntry.Id + 3463 == flag) ||
(((TopicItem)i).TopicEntry.Type != TopicType.Main && ((TopicItem)i).TopicEntry.Id + 3451 == flag)));
if (readTopic is not null)
{
return $"{readTopic.DisplayName} Watched in Extras";
return string.Format(project.Localize("{0} Watched in Extras"), readTopic.DisplayName);
}

BackgroundMusicItem bgm = (BackgroundMusicItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.BGM && ((BackgroundMusicItem)i).Flag == flag);
if (bgm is not null)
{
return $"Listened to {bgm.DisplayName}";
return string.Format(project.Localize("Listened to {0}"), bgm.DisplayName);
}

BackgroundItem bg = (BackgroundItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Background && ((BackgroundItem)i).Flag == flag);
if (bg is not null && flag > 0)
{
return $"{bg.CgName} ({bg.DisplayName}) Seen";
return string.Format(project.Localize("{0} ({1}) Seen"), bg.CgName, bg.DisplayName);
}

GroupSelectionItem groupSelection = (GroupSelectionItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Group_Selection &&
((GroupSelectionItem)i).Selection.Activities.Any(a => a?.Routes.Any(r => r?.Flag == flag) ?? false));
if (groupSelection is not null)
{
ScenarioRoute route = groupSelection.Selection.Activities.First(a => a?.Routes.Any(r => r.Flag == flag) ?? false).Routes.First(r => r.Flag == flag);
return $"Route \"{route.Title.GetSubstitutedString(project)}\" Completed";
return string.Format(project.Localize("Route \"{0}\" Completed"), route.Title.GetSubstitutedString(project));
}

ScriptItem script = (ScriptItem)project.Items.FirstOrDefault(i => i.Type == ItemDescription.ItemType.Script &&
flag >= ((ScriptItem)i).StartReadFlag && flag < ((ScriptItem)i).StartReadFlag + ((ScriptItem)i).Event.ScriptSections.Count);
if (script is not null)
{
return string.Format(project.Localize("Script {0} Section {1} Completed"), script.DisplayName, script.Event.ScriptSections[flag - script.StartReadFlag].Name);
}

return $"F{flag:D2}";
Expand Down
20 changes: 19 additions & 1 deletion src/SerialLoops.Lib/Items/ScriptItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ namespace SerialLoops.Lib.Items
public class ScriptItem : Item
{
public EventFile Event { get; set; }
public short StartReadFlag { get; set; }
public short SfxGroupIndex { get; set; }
public AdjacencyGraph<ScriptSection, ScriptSectionEdge> Graph { get; set; } = new();
private readonly Func<string, string> _localize;

public ScriptItem(string name) : base(name, ItemType.Script)
{
}
public ScriptItem(EventFile evt, Func<string, string> localize, ILogger log) : base(evt.Name[0..^1], ItemType.Script)
public ScriptItem(EventFile evt, EventTable evtTbl, Func<string, string> localize, ILogger log) : base(evt.Name[0..^1], ItemType.Script)
{
Event = evt;
UpdateEventTableInfo(evtTbl);
_localize = localize;

PruneLabelsSection(log);
Expand Down Expand Up @@ -719,6 +722,21 @@ public static (SKBitmap PreviewImage, string ErrorImage) GeneratePreviewImage(Sc
return GeneratePreviewImage(GetScriptPreview(commandTree, currentCommand, project, log), project);
}

public void UpdateEventTableInfo(EventTable evtTbl)
{
EventTableEntry entry = evtTbl.Entries.FirstOrDefault(e => e.EventFileIndex == Event.Index);
if (entry is not null)
{
StartReadFlag = entry.FirstReadFlag;
SfxGroupIndex = entry.SfxGroupIndex;
}
else
{
StartReadFlag = -1;
SfxGroupIndex = -1;
}
}

public void PruneLabelsSection(ILogger log)
{
if ((Event.LabelsSection?.Objects?.Count ?? 0) - 1 > Event.ScriptSections.Count)
Expand Down
41 changes: 38 additions & 3 deletions src/SerialLoops.Lib/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public class Project
[JsonIgnore]
public CharacterDataFile ChrData { get; set; }
[JsonIgnore]
public EventFile EventTableFile { get; set; }
[JsonIgnore]
public ExtraFile Extra { get; set; }
[JsonIgnore]
public ScenarioStruct Scenario { get; set; }
Expand All @@ -99,6 +101,8 @@ public class Project
[JsonIgnore]
public Func<string, string> Localize { get; set; }

private static readonly string[] NON_SCRIPT_EVT_FILES = new string[] { "CHESSS", "EVTTBLS", "TOPICS", "SCENARIOS", "TUTORIALS", "VOICEMAPS" };

public Project()
{
}
Expand Down Expand Up @@ -364,7 +368,17 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker)
}
tracker.Finished++;

tracker.Focus("Static Files", 5);
tracker.Focus("Static Files", 6);
try
{
EventTableFile = Evt.GetFileByName("EVTTBLS");
EventTableFile.InitializeEventTableFile();
}
catch (Exception ex)
{
log.LogException($"Failed to load event table file", ex);
}
tracker.Finished++;
try
{
ChrData = Dat.GetFileByName("CHRDATAS").CastTo<CharacterDataFile>();
Expand Down Expand Up @@ -590,11 +604,11 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker)
{
tracker.Focus("Scripts", Evt.Files.Count - 5);
Items.AddRange(Evt.Files.AsParallel()
.Where(e => !new string[] { "CHESSS", "EVTTBLS", "TOPICS", "SCENARIOS", "TUTORIALS", "VOICEMAPS" }.Contains(e.Name))
.Where(e => !NON_SCRIPT_EVT_FILES.Contains(e.Name))
.Select(e =>
{
tracker.Finished++;
return new ScriptItem(e, Localize, log);
return new ScriptItem(e, EventTableFile.EvtTbl, Localize, log);
}));
}
catch (Exception ex)
Expand Down Expand Up @@ -894,6 +908,27 @@ public bool VoiceMapIsV06OrHigher()
return Evt.Files.AsParallel().Any(f => f.Name == "VOICEMAPS") && Encoding.ASCII.GetString(Evt.GetFileByName("VOICEMAPS").Data.Skip(0x08).Take(4).ToArray()) == "SUBS";
}

public void RecalculateEventTable()
{
short currentFlag = 0;
int prevScriptIndex = 0;
foreach (EventTableEntry entry in EventTableFile.EvtTbl.Entries)
{
if (currentFlag == 0 && entry.FirstReadFlag > 0)
{
currentFlag = entry.FirstReadFlag;
prevScriptIndex = entry.EventFileIndex;
}
else if (entry.FirstReadFlag > 0)
{
currentFlag += (short)(Evt.GetFileByIndex(prevScriptIndex).ScriptSections.Count + 1);
entry.FirstReadFlag = currentFlag;
prevScriptIndex = entry.EventFileIndex;
}
}
Items.Where(i => i.Type == ItemDescription.ItemType.Script).Cast<ScriptItem>().ToList().ForEach(s => s.UpdateEventTableInfo(EventTableFile.EvtTbl));
}

public void MigrateProject(string newRom, ILogger log, IProgressTracker tracker)
{
log.Log($"Attempting to migrate base ROM to {newRom}");
Expand Down
4 changes: 2 additions & 2 deletions src/SerialLoops/Dialogs/SaveSlotEditorDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,14 @@ private List<TableRow> GetFlagBoxes(int start, int end)
private List<int> GetFilteredFlags(string term = null, bool onlyShowSet = false)
{
List<int> filtered = [];
for (int i = 0; i < 5120; i++)
for (int i = 0; i < Flags.NUM_FLAGS; i++)
{
if (onlyShowSet && !(_flagModifications.TryGetValue(i, out var set) ? set : _saveSection.IsFlagSet(i)))
{
continue;
}

if (!string.IsNullOrWhiteSpace(term) && !Flags.GetFlagNickname(i, _project).ToLower().Contains(term.ToLower().Trim()))
if (!string.IsNullOrWhiteSpace(term) && !Flags.GetFlagNickname(i, _project).Contains(term.Trim(), StringComparison.CurrentCultureIgnoreCase))
{
continue;
}
Expand Down
90 changes: 89 additions & 1 deletion src/SerialLoops/Editors/ScriptEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class ScriptEditor(ScriptItem item, ILogger log, Project project, EditorT
private TableLayout _detailsLayout = new();
private readonly StackLayout _preview = new() { Items = { new SKGuiImage(new(256, 384)) } };
private StackLayout _scriptProperties = new();
private StackLayout _eventTableProperties = new();
private StackLayout _editorControls = new();
private ScriptCommandListPanel _commandsPanel;
private Button _addCommandButton;
Expand Down Expand Up @@ -103,10 +104,42 @@ private Container GetCommandsContainer()
_detailsLayout = new() { Spacing = new Size(5, 5) };
_editorControls = new() { Orientation = Orientation.Horizontal };

_eventTableProperties = new()
{
Orientation = Orientation.Vertical,
Spacing = 5,
};
if (_script.SfxGroupIndex >= 0)
{
SetupEventTableProperties();
}
else
{
Button button = new() { Text = Application.Instance.Localize(this, "Add to Event Table") };
button.Click += (sender, args) =>
{
// we insert before the last entry which is the "end of table" entry
_project.EventTableFile.EvtTbl.Entries.Insert(_project.EventTableFile.EvtTbl.Entries.Count - 1, new((short)_script.Event.Index, 8, 1));
SetupEventTableProperties();
};
_eventTableProperties.Items.Clear();
_eventTableProperties.Items.Add(new Label { Text = Application.Instance.Localize(this, "This script is not included in the event table.") });
_eventTableProperties.Items.Add(button);
}

TabControl propertiesTabs = GetPropertiesTabs();
if (propertiesTabs.Pages.Count > 0)
{
_scriptProperties = new() { Items = { GetPropertiesTabs() } };
_scriptProperties = new()
{
Orientation = Orientation.Vertical,
Spacing = 10,
Items =
{
GetPropertiesTabs(),
_eventTableProperties,
},
};
}

_detailsLayout.Rows.Add(new(new TableLayout(new TableRow(_preview, _scriptProperties))));
Expand All @@ -117,6 +150,61 @@ private Container GetCommandsContainer()
return layout;
}

private void SetupEventTableProperties()
{
DropDown sfxGroupDropDown = new();
sfxGroupDropDown.Items.AddRange(_project.Snd.Groups.Select(g => new ListItem { Key = g.Name, Text = g.Name }));
sfxGroupDropDown.SelectedIndex = _script.SfxGroupIndex;
sfxGroupDropDown.SelectedIndexChanged += (sender, args) =>
{
_project.EventTableFile.EvtTbl.Entries.First(e => e.EventFileIndex == _script.Event.Index).SfxGroupIndex = (short)sfxGroupDropDown.SelectedIndex;
UpdateTabTitle(false);
};

StackLayout readFlagLayout = new() { Orientation = Orientation.Horizontal, Spacing = 3 };
if (_script.StartReadFlag > 0)
{
SetupReadFlagLayout(readFlagLayout);
}
else
{
SetupAddReadFlagLayout(readFlagLayout);
}

_eventTableProperties.Items.Clear();
_eventTableProperties.Items.Add(readFlagLayout);
_eventTableProperties.Items.Add(ControlGenerator.GetControlWithLabel(Application.Instance.Localize(this, "SFX Group"), sfxGroupDropDown));
}

private void SetupReadFlagLayout(StackLayout readFlagLayout)
{
readFlagLayout.Items.Add(ControlGenerator.GetControlWithLabel(Application.Instance.Localize(this, "Start Read Flag"), _script.StartReadFlag.ToString()));
Button button = new() { Text = Application.Instance.Localize(this, "Remove Read Flag") };
button.Click += (sender, args) =>
{
_project.EventTableFile.EvtTbl.Entries.First(e => e.EventFileIndex == _script.Event.Index).FirstReadFlag = -1;
_script.StartReadFlag = -1;
readFlagLayout.Items.Clear();
SetupAddReadFlagLayout(readFlagLayout);
UpdateTabTitle(false);
};
readFlagLayout.Items.Add(button);
}

private void SetupAddReadFlagLayout(StackLayout readFlagLayout)
{
Button button = new() { Text = Application.Instance.Localize(this, "Add Read Flag") };
button.Click += (sender, args) =>
{
_project.EventTableFile.EvtTbl.Entries.First(e => e.EventFileIndex == _script.Event.Index).FirstReadFlag = 1;
_script.StartReadFlag = 1;
readFlagLayout.Items.Clear();
SetupReadFlagLayout(readFlagLayout);
UpdateTabTitle(false);
};
readFlagLayout.Items.Add(button);
}

private StackLayout GetEditorButtons(ScriptCommandSectionTreeGridView treeGridView)
{
_addCommandButton = new()
Expand Down
Loading

0 comments on commit bb6e2a3

Please sign in to comment.