mirror of
https://github.com/ficed/Braver.git
synced 2024-12-04 11:23:22 +00:00
Load item data
Rework cacheable singletons Very basic character combatant in sim
This commit is contained in:
parent
f14a63bae2
commit
db9a5c25ad
@ -13,13 +13,43 @@ namespace Braver {
|
||||
}
|
||||
|
||||
public abstract class BGame {
|
||||
|
||||
protected class LGPDataSource : DataSource {
|
||||
private Ficedula.FF7.LGPFile _lgp;
|
||||
|
||||
public LGPDataSource(Ficedula.FF7.LGPFile lgp) {
|
||||
_lgp = lgp;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Scan() => _lgp.Filenames;
|
||||
public override Stream TryOpen(string file) => _lgp.TryOpen(file);
|
||||
}
|
||||
|
||||
protected class FileDataSource : DataSource {
|
||||
private string _root;
|
||||
|
||||
public FileDataSource(string root) {
|
||||
_root = root;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Scan() {
|
||||
//TODO subdirectories
|
||||
return Directory.GetFiles(_root).Select(s => Path.GetFileName(s));
|
||||
}
|
||||
|
||||
public override Stream TryOpen(string file) {
|
||||
string fn = Path.Combine(_root, file);
|
||||
if (File.Exists(fn))
|
||||
return new FileStream(fn, FileMode.Open, FileAccess.Read);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public VMM Memory { get; } = new();
|
||||
public SaveMap SaveMap { get; }
|
||||
|
||||
public SaveData SaveData { get; private set; }
|
||||
public SaveData SaveData { get; protected set; }
|
||||
protected Dictionary<string, List<DataSource>> _data = new Dictionary<string, List<DataSource>>(StringComparer.InvariantCultureIgnoreCase);
|
||||
private Dictionary<Type, object> _singletons = new();
|
||||
private Dictionary<Type, Dictionary<int, CacheItem>> _cacheItems = new();
|
||||
|
||||
public BGame() {
|
||||
SaveMap = new SaveMap(Memory);
|
||||
@ -42,6 +72,14 @@ namespace Braver {
|
||||
SaveData.Loaded();
|
||||
}
|
||||
|
||||
public T Singleton<T>() where T : Cacheable, new() {
|
||||
return Singleton<T>(() => {
|
||||
T t = new T();
|
||||
t.Init(this);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
public T Singleton<T>(Func<T> create) {
|
||||
if (_singletons.TryGetValue(typeof(T), out object obj))
|
||||
return (T)obj;
|
||||
@ -52,17 +90,6 @@ namespace Braver {
|
||||
}
|
||||
}
|
||||
|
||||
public T CacheItem<T>(int id) where T : CacheItem, new() {
|
||||
if (!_cacheItems.TryGetValue(typeof(T), out var dict))
|
||||
dict = _cacheItems[typeof(T)] = new Dictionary<int, CacheItem>();
|
||||
if (!dict.TryGetValue(id, out var item)) {
|
||||
T t = new T();
|
||||
t.Init(this, id);
|
||||
item = dict[id] = t;
|
||||
}
|
||||
return (T)item;
|
||||
}
|
||||
|
||||
|
||||
public void NewGame() {
|
||||
using (var s = Open("save", "newgame.xml"))
|
||||
@ -104,22 +131,8 @@ namespace Braver {
|
||||
|
||||
}
|
||||
|
||||
public abstract class CacheItem {
|
||||
public abstract void Init(BGame g, int index);
|
||||
public abstract class Cacheable {
|
||||
public abstract void Init(BGame g);
|
||||
}
|
||||
|
||||
public class GameText {
|
||||
private List<Ficedula.FF7.KernelText> _texts = new();
|
||||
public GameText(BGame g) {
|
||||
var kernel = new Ficedula.FF7.Kernel(g.Open("kernel", "kernel.bin"));
|
||||
_texts.AddRange(Enumerable.Repeat<Ficedula.FF7.KernelText>(null, 9));
|
||||
_texts.AddRange(
|
||||
kernel.Sections
|
||||
.Skip(9)
|
||||
.Select(section => new Ficedula.FF7.KernelText(section))
|
||||
);
|
||||
}
|
||||
|
||||
public string Get(int section, int item) => _texts[section].Get(item);
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,18 @@ namespace Braver.Battle {
|
||||
public Statuses Statuses { get; set; }
|
||||
}
|
||||
|
||||
public class CharacterActionItem {
|
||||
public int ID { get; set; }
|
||||
public Ability Ability { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class CharacterAction {
|
||||
public Ability? Ability { get; set; }
|
||||
public string Name { get; set; }
|
||||
public List<CharacterActionItem> SubMenu { get; set; }
|
||||
}
|
||||
|
||||
public class CharacterCombatant : ICombatant {
|
||||
|
||||
private Character _char;
|
||||
@ -67,23 +79,62 @@ namespace Braver.Battle {
|
||||
|
||||
public string Name => _char.Name;
|
||||
|
||||
public CharacterCombatant(Character chr) {
|
||||
public List<CharacterAction> Actions { get; } = new();
|
||||
|
||||
public CharacterCombatant(BGame g, Character chr) {
|
||||
_char = chr;
|
||||
|
||||
var weapon = chr.GetWeapon(g);
|
||||
var armour = chr.GetArmour(g);
|
||||
var accessory = chr.GetAccessory(g);
|
||||
|
||||
_stats = new CombatStats {
|
||||
Dex = chr.Dexterity,
|
||||
Lck = chr.Luck,
|
||||
Level = chr.Level,
|
||||
CriticalChance = 0, //TODO weapon crit%
|
||||
Att = 90, //TODO Str + Weapon Attack Bonus
|
||||
Def = chr.Vitality, //TODO Vit + Armour Defense Bonus
|
||||
DfPC = chr.Dexterity / 4, //TODO [Dex / 4] + Armour Defense% Bonus
|
||||
CriticalChance = weapon.CriticalChance,
|
||||
Att = chr.Strength + (weapon?.AttackStrength ?? 0),
|
||||
Def = chr.Vitality + (armour?.Defense ?? 0),
|
||||
DfPC = chr.Dexterity / 4 + (armour?.DefensePercent ?? 0),
|
||||
MAt = chr.Spirit,
|
||||
MDf = chr.Spirit, //TODO Spr + Armour MDefense Bonus
|
||||
MDPC = 0, //TODO Armour MDefense% Bonus
|
||||
MDf = chr.Spirit + (armour?.MDefense ?? 0),
|
||||
MDPC = armour?.MDefensePercent ?? 0,
|
||||
};
|
||||
|
||||
//Attack action: //AtPC = 90, //TODO weapon at%,
|
||||
|
||||
Actions.Add(new CharacterAction {
|
||||
Name = "Attack",
|
||||
Ability = new Ability {
|
||||
PAtPercent = (byte)weapon.HitChance,
|
||||
Power = (byte)(chr.Strength + weapon.AttackStrength),
|
||||
IsPhysical = true,
|
||||
Elements = new HashSet<Element>(weapon.Elements.Split()),
|
||||
LongRange = !weapon.TargettingFlags.HasFlag(TargettingFlags.ShortRange),
|
||||
InflictStatus = weapon.Statuses,
|
||||
Formula = AttackFormula.Physical, //TODO
|
||||
}
|
||||
});
|
||||
Actions.Add(new CharacterAction {
|
||||
Name = "Item",
|
||||
SubMenu = g.SaveData
|
||||
.Inventory
|
||||
.Where(inv => inv.Kind == InventoryItemKind.Item)
|
||||
.Select(inv => g.Singleton<Items>()[inv.ItemID])
|
||||
.Where(item => item.Restrictions.HasFlag(EquipRestrictions.CanUseInBattle))
|
||||
.Select(item => {
|
||||
return new CharacterActionItem {
|
||||
ID = item.ID,
|
||||
Ability = new Ability {
|
||||
Power = item.Power,
|
||||
Elements = new HashSet<Element>(item.Elements.Split()),
|
||||
StatusChance = item.StatusChance,
|
||||
InflictStatus = item.StatusType == AttackStatusType.Inflict ? item.Statuses : Statuses.None,
|
||||
RemoveStatus = item.StatusType == AttackStatusType.Cure ? item.Statuses : Statuses.None,
|
||||
ToggleStatus = item.StatusType == AttackStatusType.Toggle ? item.Statuses : Statuses.None,
|
||||
}
|
||||
};
|
||||
})
|
||||
.ToList()
|
||||
});
|
||||
}
|
||||
|
||||
public CombatStats BaseStats => _stats;
|
||||
|
@ -1,15 +1,9 @@
|
||||
using Ficedula.FF7;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace Braver.Battle {
|
||||
public class Engine {
|
||||
|
@ -43,6 +43,10 @@ namespace Braver.Battle {
|
||||
});
|
||||
}
|
||||
|
||||
public void Reset() {
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
if (_value < _max) {
|
||||
_value += _increment;
|
||||
|
@ -1,31 +1,92 @@
|
||||
using System;
|
||||
using Ficedula.FF7;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Braver {
|
||||
public class Item : CacheItem {
|
||||
|
||||
public class KeyItem {
|
||||
public string Name { get; init; }
|
||||
public string Description { get; init; }
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string Description { get; private set; }
|
||||
public class KernelCache : Cacheable {
|
||||
public Kernel Kernel { get; private set; }
|
||||
|
||||
public override void Init(BGame g, int index) {
|
||||
var text = g.Singleton<GameText>(() => new GameText(g));
|
||||
Name = text.Get(19, index);
|
||||
Description = text.Get(11, index);
|
||||
public override void Init(BGame g) {
|
||||
Kernel = new Kernel(g.Open("kernel", "kernel.bin"));
|
||||
}
|
||||
}
|
||||
|
||||
public class KeyItem : CacheItem {
|
||||
public class KeyItems : Cacheable {
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string Description { get; private set; }
|
||||
private List<KeyItem> _keyitems = new();
|
||||
|
||||
public override void Init(BGame g, int index) {
|
||||
var text = g.Singleton<GameText>(() => new GameText(g));
|
||||
Name = text.Get(24, index);
|
||||
Description = text.Get(16, index);
|
||||
public IReadOnlyList<KeyItem> Items => _keyitems.AsReadOnly();
|
||||
|
||||
public override void Init(BGame g) {
|
||||
var kernel = g.Singleton<KernelCache>();
|
||||
var names = new KernelText(kernel.Kernel.Sections[24]);
|
||||
var descriptions = new KernelText(kernel.Kernel.Sections[16]);
|
||||
|
||||
_keyitems = Enumerable.Range(0, names.Count)
|
||||
.Select(i => new KeyItem {
|
||||
Name = names.Get(i),
|
||||
Description = descriptions.Get(i),
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Items : Cacheable {
|
||||
private ItemCollection _items;
|
||||
|
||||
public Item this[int index] => _items.Items[index];
|
||||
public int Count => _items.Items.Count;
|
||||
|
||||
public override void Init(BGame g) {
|
||||
var kernel = g.Singleton<KernelCache>();
|
||||
_items = new ItemCollection(kernel.Kernel);
|
||||
}
|
||||
}
|
||||
|
||||
public class Weapons : Cacheable {
|
||||
private WeaponCollection _weapons;
|
||||
|
||||
public Weapon this[int index] => _weapons.Weapons[index];
|
||||
public int Count => _weapons.Weapons.Count;
|
||||
|
||||
public override void Init(BGame g) {
|
||||
var kernel = g.Singleton<KernelCache>();
|
||||
_weapons = new WeaponCollection(kernel.Kernel);
|
||||
}
|
||||
}
|
||||
|
||||
public class Armours : Cacheable {
|
||||
private ArmourCollection _armours;
|
||||
|
||||
public Armour this[int index] => _armours.Armour[index];
|
||||
public int Count => _armours.Armour.Count;
|
||||
|
||||
public override void Init(BGame g) {
|
||||
var kernel = g.Singleton<KernelCache>();
|
||||
_armours = new ArmourCollection(kernel.Kernel);
|
||||
}
|
||||
}
|
||||
|
||||
public class Accessories : Cacheable {
|
||||
private AccessoryCollection _accessories;
|
||||
|
||||
public Accessory this[int index] => _accessories.Accessories[index];
|
||||
public int Count => _accessories.Accessories.Count;
|
||||
|
||||
public override void Init(BGame g) {
|
||||
var kernel = g.Singleton<KernelCache>();
|
||||
_accessories = new AccessoryCollection(kernel.Kernel);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Ficedula.FF7;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -143,6 +144,16 @@ namespace Braver {
|
||||
|
||||
[XmlIgnore]
|
||||
public bool IsBackRow => Flags.HasFlag(CharFlags.BackRow);
|
||||
|
||||
public Weapon GetWeapon(BGame game) {
|
||||
return EquipWeapon < 0 ? null : game.Singleton<Weapons>()[EquipWeapon];
|
||||
}
|
||||
public Armour GetArmour(BGame game) {
|
||||
return EquipArmour < 0 ? null : game.Singleton<Armours>()[EquipArmour];
|
||||
}
|
||||
public Accessory GetAccessory(BGame game) {
|
||||
return EquipAccessory < 0 ? null : game.Singleton<Accessories>()[EquipAccessory];
|
||||
}
|
||||
}
|
||||
|
||||
public class SaveData {
|
||||
|
@ -1,17 +1,20 @@
|
||||
// Usage: BraverBattleSim [DataFolder] [EncounterNumber] [SaveDataFile]
|
||||
using Braver;
|
||||
using Braver.Battle;
|
||||
using Ficedula.FF7.Battle;
|
||||
using System;
|
||||
|
||||
Console.WriteLine("Braver Battle Sim");
|
||||
|
||||
var scene = Ficedula.FF7.Battle.SceneDecoder.Decode(File.OpenRead(Path.Combine(args[0], "battle", "scene.bin")))
|
||||
var game = new SimGame(args[0]);
|
||||
game.Start(args[2]);
|
||||
|
||||
var scene = Ficedula.FF7.Battle.SceneDecoder.Decode(game.Open("battle", "scene.bin"))
|
||||
.ElementAt(int.Parse(args[1]));
|
||||
|
||||
var saveData = Serialisation.Deserialise<SaveData>(File.OpenRead(args[2]));
|
||||
|
||||
var chars = saveData
|
||||
var chars = game.SaveData
|
||||
.Party
|
||||
.Select(c => new CharacterCombatant(c));
|
||||
.Select(c => new CharacterCombatant(game, c));
|
||||
|
||||
var enemies = scene
|
||||
.Enemies
|
||||
@ -25,7 +28,31 @@ while (true) {
|
||||
var ready = engine.Combatants.Where(c => c.TTimer.IsFull);
|
||||
if (ready.Any()) {
|
||||
Console.WriteLine($"At {engine.GTimer.Ticks} gticks, {string.Join(", ", ready.Select(c => c.Name))} ready to act");
|
||||
foreach(var enemy in ready.OfType<EnemyCombatant>()) {
|
||||
|
||||
foreach(var chr in ready.OfType<CharacterCombatant>()) {
|
||||
Console.WriteLine(chr.Name);
|
||||
var ability = MenuChoose(chr);
|
||||
Console.WriteLine("Targets:");
|
||||
Console.WriteLine(string.Join(" ", engine.Combatants.Select((comb, index) => $"{(char)('A' + index)}:{comb.Name}")));
|
||||
var targets = Console.ReadLine()
|
||||
.Trim()
|
||||
.ToUpper()
|
||||
.Split(' ')
|
||||
.Select(s => s[0])
|
||||
.Select(c => engine.Combatants.ElementAt(c - 'A'));
|
||||
var results = engine.ApplyAbility(
|
||||
chr,
|
||||
ability,
|
||||
targets
|
||||
);
|
||||
foreach (var result in results) {
|
||||
Console.WriteLine($"--Target {result.Target}, hit {result.Hit}, inflict {result.InflictStatus} remove {result.RemoveStatus} recovery {result.Recovery}, damage HP {result.HPDamage} MP {result.MPDamage}");
|
||||
}
|
||||
chr.TTimer.Reset();
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
foreach (var enemy in ready.OfType<EnemyCombatant>()) {
|
||||
//TODO AI
|
||||
var action = enemy.Enemy.Enemy.Actions[0];
|
||||
var target = engine.Combatants
|
||||
@ -42,7 +69,44 @@ while (true) {
|
||||
foreach(var result in results) {
|
||||
Console.WriteLine($"--Target {result.Target}, hit {result.Hit}, inflict {result.InflictStatus} remove {result.RemoveStatus} recovery {result.Recovery}, damage HP {result.HPDamage} MP {result.MPDamage}");
|
||||
}
|
||||
enemy.TTimer.Reset();
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Ability MenuChoose(CharacterCombatant chr) {
|
||||
char c = 'A';
|
||||
foreach (var action in chr.Actions) {
|
||||
Console.WriteLine($" {c++}: {action.Name}");
|
||||
}
|
||||
char choice = Console.ReadLine().Trim().ToUpper().First();
|
||||
var chosen = chr.Actions[choice - 'A'];
|
||||
if (chosen.Ability != null)
|
||||
return chosen.Ability.Value;
|
||||
|
||||
c = 'A';
|
||||
foreach(var sub in chosen.SubMenu) {
|
||||
Console.WriteLine($" {c++}: {sub.Name}");
|
||||
}
|
||||
choice = Console.ReadLine().Trim().ToUpper().First();
|
||||
var subchosen = chosen.SubMenu[choice - 'A'];
|
||||
return subchosen.Ability;
|
||||
}
|
||||
|
||||
public class SimGame : BGame {
|
||||
public SimGame(string data) {
|
||||
_data["battle"] = new List<DataSource> {
|
||||
new LGPDataSource(new Ficedula.FF7.LGPFile(Path.Combine(data, "battle", "battle.lgp"))),
|
||||
new FileDataSource(Path.Combine(data, "battle"))
|
||||
};
|
||||
_data["kernel"] = new List<DataSource> {
|
||||
new FileDataSource(Path.Combine(data, "kernel"))
|
||||
};
|
||||
}
|
||||
|
||||
public void Start(string savegame) {
|
||||
SaveData = Serialisation.Deserialise<SaveData>(File.OpenRead(savegame));
|
||||
}
|
||||
}
|
||||
|
31
F7/FGame.cs
31
F7/FGame.cs
@ -23,37 +23,6 @@ namespace Braver {
|
||||
|
||||
public class FGame : BGame {
|
||||
|
||||
private class LGPDataSource : DataSource {
|
||||
private Ficedula.FF7.LGPFile _lgp;
|
||||
|
||||
public LGPDataSource(Ficedula.FF7.LGPFile lgp) {
|
||||
_lgp = lgp;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Scan() => _lgp.Filenames;
|
||||
public override Stream TryOpen(string file) => _lgp.TryOpen(file);
|
||||
}
|
||||
|
||||
private class FileDataSource : DataSource {
|
||||
private string _root;
|
||||
|
||||
public FileDataSource(string root) {
|
||||
_root = root;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Scan() {
|
||||
//TODO subdirectories
|
||||
return Directory.GetFiles(_root).Select(s => Path.GetFileName(s));
|
||||
}
|
||||
|
||||
public override Stream TryOpen(string file) {
|
||||
string fn = Path.Combine(_root, file);
|
||||
if (File.Exists(fn))
|
||||
return new FileStream(fn, FileMode.Open, FileAccess.Read);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Stack<Screen> _screens = new();
|
||||
private Microsoft.Xna.Framework.Graphics.GraphicsDevice _graphics;
|
||||
|
||||
|
@ -20,14 +20,10 @@ namespace Braver.UI.Layout {
|
||||
|
||||
public override bool IsRazorModel => true;
|
||||
|
||||
private WeaponCollection _weapons;
|
||||
private ArmourCollection _armours;
|
||||
private AccessoryCollection _accessories;
|
||||
|
||||
public Character Character => _game.SaveData.Party[(int)_screen.Param];
|
||||
public Weapon Weapon => _weapons.Weapons.ElementAtOrDefault(Character.EquipWeapon);
|
||||
public Armour Armour => _armours.Armour.ElementAtOrDefault(Character.EquipArmour);
|
||||
public Accessory Accessory => _accessories.Accessories.ElementAtOrDefault(Character.EquipAccessory);
|
||||
public Weapon Weapon => Character.GetWeapon(_game);
|
||||
public Armour Armour => Character.GetArmour(_game);
|
||||
public Accessory Accessory => Character.GetAccessory(_game);
|
||||
|
||||
public List<Weapon> AvailableWeapons { get; } = new();
|
||||
public List<Armour> AvailableArmour { get; } = new();
|
||||
@ -35,10 +31,11 @@ namespace Braver.UI.Layout {
|
||||
|
||||
public override void Created(FGame g, LayoutScreen screen) {
|
||||
base.Created(g, screen);
|
||||
|
||||
var kernel = _game.Singleton(() => new Kernel(_game.Open("kernel", "kernel.bin")));
|
||||
_weapons = _game.Singleton(() => new WeaponCollection(kernel));
|
||||
_armours = _game.Singleton(() => new ArmourCollection(kernel));
|
||||
_accessories = _game.Singleton(() => new AccessoryCollection(kernel));
|
||||
var weapons = _game.Singleton(() => new WeaponCollection(kernel));
|
||||
var armours = _game.Singleton(() => new ArmourCollection(kernel));
|
||||
var accessories = _game.Singleton(() => new AccessoryCollection(kernel));
|
||||
|
||||
AvailableWeapons.Clear();
|
||||
AvailableWeapons.AddRange(
|
||||
@ -49,7 +46,7 @@ namespace Braver.UI.Layout {
|
||||
.Where(id => id >= 0)
|
||||
.Distinct()
|
||||
.OrderBy(i => i)
|
||||
.Select(i => _weapons.Weapons[i])
|
||||
.Select(i => weapons.Weapons[i])
|
||||
);
|
||||
|
||||
AvailableArmour.Clear();
|
||||
@ -61,7 +58,7 @@ namespace Braver.UI.Layout {
|
||||
.Where(id => id >= 0)
|
||||
.Distinct()
|
||||
.OrderBy(i => i)
|
||||
.Select(i => _armours.Armour[i])
|
||||
.Select(i => armours.Armour[i])
|
||||
);
|
||||
|
||||
AvailableAccessories.Clear();
|
||||
@ -73,7 +70,7 @@ namespace Braver.UI.Layout {
|
||||
.Where(id => id >= 0)
|
||||
.Distinct()
|
||||
.OrderBy(i => i)
|
||||
.Select(i => _accessories.Accessories[i])
|
||||
.Select(i => accessories.Accessories[i])
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -64,24 +64,18 @@ namespace Braver.UI.Layout {
|
||||
|
||||
public static (string Item, string Description) GetInventory(FGame game, int index) {
|
||||
var inv = game.SaveData.Inventory[index];
|
||||
switch (inv.Kind) {
|
||||
switch (inv.Kind) {
|
||||
case InventoryItemKind.Item:
|
||||
var item = game.CacheItem<Item>(inv.ItemID);
|
||||
var item = game.Singleton<Items>()[inv.ItemID];
|
||||
return (item.Name, item.Description);
|
||||
case InventoryItemKind.Weapon:
|
||||
var kernel = game.Singleton(() => new Kernel(game.Open("kernel", "kernel.bin")));
|
||||
var weapons = game.Singleton(() => new WeaponCollection(kernel));
|
||||
var weapon = weapons.Weapons[index];
|
||||
var weapon = game.Singleton<Weapons>()[inv.ItemID];
|
||||
return (weapon.Name, weapon.Description);
|
||||
case InventoryItemKind.Armour:
|
||||
kernel = game.Singleton(() => new Kernel(game.Open("kernel", "kernel.bin")));
|
||||
var armours = game.Singleton(() => new ArmourCollection(kernel));
|
||||
var armour = armours.Armour[index];
|
||||
return (armour.Name, armour.Description);
|
||||
case InventoryItemKind.Accessory:
|
||||
kernel = game.Singleton(() => new Kernel(game.Open("kernel", "kernel.bin")));
|
||||
var accessories = game.Singleton(() => new AccessoryCollection(kernel));
|
||||
var accessory = accessories.Accessories[index];
|
||||
var armour = game.Singleton<Armours>()[inv.ItemID];
|
||||
return (armour.Name, armour.Description);
|
||||
case InventoryItemKind.Accessory:
|
||||
var accessory = game.Singleton<Accessories>()[inv.ItemID];
|
||||
return (accessory.Name, accessory.Description);
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
@ -94,7 +88,7 @@ namespace Braver.UI.Layout {
|
||||
}
|
||||
|
||||
public void KeyItemFocussed() {
|
||||
var keyItem = _game.CacheItem<KeyItem>(_game.SaveData.KeyItems[lbKeyItems.GetSelectedIndex(this)]);
|
||||
var keyItem = _game.Singleton<KeyItems>().Items[_game.SaveData.KeyItems[lbKeyItems.GetSelectedIndex(this)]];
|
||||
lDescription.Text = keyItem.Description;
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,8 @@ if (args[0].Equals("Kernel", StringComparison.OrdinalIgnoreCase)) {
|
||||
|
||||
var accessories = new Ficedula.FF7.AccessoryCollection(kernel);
|
||||
|
||||
var items = new Ficedula.FF7.ItemCollection(kernel);
|
||||
|
||||
File.WriteAllBytes(@"C:\temp\s9.bin", kernel.Sections.ElementAt(9));
|
||||
File.WriteAllBytes(@"C:\temp\s16.bin", kernel.Sections.ElementAt(16));
|
||||
|
||||
|
@ -78,6 +78,7 @@ namespace Ficedula.FF7.Battle {
|
||||
public short ActionID { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public Attack() { }
|
||||
public Attack(Stream s) {
|
||||
AttackPC = (byte)s.ReadByte();
|
||||
ImpactEffect = (byte)s.ReadByte();
|
||||
|
78
Ficedula.FF7/Item.cs
Normal file
78
Ficedula.FF7/Item.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using Ficedula.FF7.Battle;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ficedula.FF7 {
|
||||
public class Item {
|
||||
public int ID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public ushort CameraMovementID { get; set; }
|
||||
public EquipRestrictions Restrictions { get; set; }
|
||||
public TargettingFlags TargettingFlags { get; set; }
|
||||
public byte AttackEffectID { get; set; }
|
||||
public byte DamageFormula { get; set; }
|
||||
public byte Power { get; set; }
|
||||
public AttackCondition AttackCondition { get; set; }
|
||||
public AttackStatusType StatusType { get; set; }
|
||||
public byte StatusChance { get; set; }
|
||||
public Statuses Statuses { get; set; }
|
||||
public byte AdditionalEffects { get; set; }
|
||||
public byte AdditionalEffectsModifier { get; set; }
|
||||
public Elements Elements { get; set; }
|
||||
public ushort AttackFlags { get; set; }
|
||||
}
|
||||
|
||||
public class ItemCollection {
|
||||
private List<Item> _items = new();
|
||||
|
||||
public IReadOnlyList<Item> Items => _items.AsReadOnly();
|
||||
|
||||
public ItemCollection(Kernel kernel) {
|
||||
var descriptions = new KernelText(kernel.Sections.ElementAt(11));
|
||||
var names = new KernelText(kernel.Sections.ElementAt(19));
|
||||
|
||||
var data = new MemoryStream(kernel.Sections.ElementAt(4));
|
||||
|
||||
int index = 0;
|
||||
while (data.Position < data.Length) {
|
||||
Item item = new Item {
|
||||
Name = names.Get(index),
|
||||
Description = descriptions.Get(index),
|
||||
ID = index,
|
||||
};
|
||||
index++;
|
||||
|
||||
data.ReadI32();
|
||||
data.ReadI32();
|
||||
item.CameraMovementID = data.ReadU16();
|
||||
item.Restrictions = (EquipRestrictions)(~data.ReadU16() & 0x7);
|
||||
item.TargettingFlags = (TargettingFlags)data.ReadU8();
|
||||
item.AttackEffectID = data.ReadU8();
|
||||
item.DamageFormula = data.ReadU8();
|
||||
item.Power = data.ReadU8();
|
||||
item.AttackCondition = (AttackCondition)data.ReadU8();
|
||||
byte chance = data.ReadU8();
|
||||
item.StatusChance = (byte)(chance & 0x3f);
|
||||
if ((chance & 0x80) != 0)
|
||||
item.StatusType = AttackStatusType.Toggle;
|
||||
else if ((chance & 0x40) != 0)
|
||||
item.StatusType = AttackStatusType.Cure;
|
||||
else
|
||||
item.StatusType = AttackStatusType.Inflict;
|
||||
item.AdditionalEffects = data.ReadU8();
|
||||
item.AdditionalEffectsModifier = data.ReadU8();
|
||||
item.Statuses = (Statuses)data.ReadI32();
|
||||
if (chance == 0xff)
|
||||
item.Statuses = Statuses.None;
|
||||
item.Elements = (Elements)data.ReadU16();
|
||||
item.AttackFlags = data.ReadU16();
|
||||
|
||||
_items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ namespace Ficedula.FF7 {
|
||||
|
||||
private List<byte[]> _sections = new();
|
||||
|
||||
public IEnumerable<byte[]> Sections => _sections.AsReadOnly();
|
||||
public IReadOnlyList<byte[]> Sections => _sections.AsReadOnly();
|
||||
|
||||
public Kernel(Stream source) {
|
||||
while (source.Position < source.Length) {
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
<Component xsi:type="List" X="0" Y="20" W="730" H="560" ID="lbKeyItems" Visible="false">
|
||||
@foreach(int i in Enumerable.Range(0, @Model.SaveData.KeyItems.Count)) {
|
||||
<Component xsi:type="Label" Y="0" X="20" ID='@("KeyItem" + i)' Focussed="KeyItemFocussed">@(Model.CacheItem<Braver.KeyItem>(Model.SaveData.KeyItems[i]).Name)</Component>
|
||||
<Component xsi:type="Label" Y="0" X="20" ID='@("KeyItem" + i)' Focussed="KeyItemFocussed">@(Model.Singleton<Braver.KeyItems>().Items[Model.SaveData.KeyItems[i]].Name)</Component>
|
||||
}
|
||||
</Component>
|
||||
</Component>
|
||||
|
Loading…
Reference in New Issue
Block a user