feat(equipment): persist mech loadouts and recover ejection safe case loot
This commit is contained in:
@@ -11,12 +11,14 @@ namespace Ironspore
|
||||
public string uid = Guid.NewGuid().ToString("N");
|
||||
public string itemId;
|
||||
public int count;
|
||||
public int x, y;
|
||||
public bool rotated, borrowed;
|
||||
public CargoStack(string id, int amount)
|
||||
{
|
||||
itemId = id;
|
||||
count = amount;
|
||||
}
|
||||
public string Name => GameLocalization.ItemName(itemId);
|
||||
public string Name => InventoryGrid.Slot(itemId) >= 0 ? GameLocalization.Text("equipment." + itemId + ".name") : GameLocalization.ItemName(itemId);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -39,13 +41,18 @@ namespace Ironspore
|
||||
public float elapsed;
|
||||
public float escortArmor = 250;
|
||||
public List<CargoStack> cargo = new List<CargoStack>();
|
||||
public List<CargoStack> safeCase = new List<CargoStack>();
|
||||
public List<CargoStack> installed = new List<CargoStack>();
|
||||
public bool destructionPending;
|
||||
public List<string> searched = new List<string>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class GameSave
|
||||
{
|
||||
public int version = 1;
|
||||
public const int CurrentVersion = 2;
|
||||
public int version = CurrentVersion;
|
||||
public List<CargoStack> warehouse = new List<CargoStack>();
|
||||
public int alloy;
|
||||
public int cells;
|
||||
public int sorties;
|
||||
@@ -57,7 +64,7 @@ namespace Ironspore
|
||||
public RunRecord run = new RunRecord();
|
||||
}
|
||||
|
||||
public sealed class ProfileStore
|
||||
public sealed partial class ProfileStore
|
||||
{
|
||||
readonly string path;
|
||||
public GameSave Data
|
||||
@@ -69,10 +76,28 @@ namespace Ironspore
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public static string SavePath(bool trial)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string root = Path.Combine(Path.GetDirectoryName(Application.dataPath), "UserSettings");
|
||||
#else
|
||||
string root = Application.persistentDataPath;
|
||||
#endif
|
||||
return Path.Combine(root, "Ironspore", trial ? "range-v2.json" : "profile-v2.json");
|
||||
}
|
||||
|
||||
public ProfileStore(string savePath)
|
||||
{
|
||||
path = savePath;
|
||||
Data = Load(path) ?? Load(path + ".bak") ?? new GameSave();
|
||||
Data = Load(path) ?? Load(path + ".bak");
|
||||
if (Data == null)
|
||||
{
|
||||
if (File.Exists(path) || File.Exists(path + ".bak"))
|
||||
throw new InvalidDataException("No valid equipment snapshot: " + path);
|
||||
Data = new GameSave();
|
||||
for (int slot = 0; slot < 4; slot++)
|
||||
Data.warehouse.Add(new CargoStack(InventoryGrid.EquipmentId(slot, 0), 1));
|
||||
}
|
||||
}
|
||||
|
||||
static GameSave Load(string file)
|
||||
@@ -82,19 +107,25 @@ namespace Ironspore
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
var save = JsonUtility.FromJson<GameSave>(File.ReadAllText(file));
|
||||
if (save == null || save.version != 1 || save.run == null || save.receipts == null || save.blueprints == null || save.unlocked == null)
|
||||
return null;
|
||||
if (save.run.cargo == null || save.run.equipment == null || save.run.equipment.Length != 4)
|
||||
return null;
|
||||
if (save != null && save.version != GameSave.CurrentVersion)
|
||||
throw new NotSupportedException("Unsupported equipment save version: " + save.version);
|
||||
if (!Valid(save)) return null;
|
||||
return save;
|
||||
}
|
||||
catch (Exception) { return null; }
|
||||
catch (ArgumentException) { return null; }
|
||||
}
|
||||
|
||||
public bool Commit(Func<GameSave, bool> change)
|
||||
{
|
||||
if (Data.run.destructionPending) return false;
|
||||
return Write(change);
|
||||
}
|
||||
|
||||
bool Write(Func<GameSave, bool> change)
|
||||
{
|
||||
Error = null;
|
||||
var candidate = JsonUtility.FromJson<GameSave>(JsonUtility.ToJson(Data));
|
||||
if (!change(candidate))
|
||||
if (!change(candidate) || !Valid(candidate))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
@@ -107,7 +138,7 @@ namespace Ironspore
|
||||
stream.Flush(true);
|
||||
}
|
||||
if (File.Exists(path))
|
||||
File.Replace(temp, path, path + ".bak");
|
||||
File.Replace(temp, path, Load(path) == null ? null : path + ".bak");
|
||||
else
|
||||
File.Move(temp, path);
|
||||
Data = candidate;
|
||||
@@ -117,102 +148,31 @@ namespace Ironspore
|
||||
catch (Exception ex) { Error = ex.Message; return false; }
|
||||
}
|
||||
|
||||
public bool Begin(int chassis, int[] equipment, float armor, int seed)
|
||||
public bool Begin(int chassis, int[] equipment, float armor, int seed, bool trial = false, string[] selected = null)
|
||||
{
|
||||
return Commit(s =>
|
||||
{
|
||||
if ((selected != null && selected.Length != 4) || s.run.active || equipment == null || equipment.Length != 4 || armor <= 0) return false;
|
||||
s.run = new RunRecord { id = Guid.NewGuid().ToString("N"), active = true, seed = seed, chassis = chassis, equipment = (int[])equipment.Clone(), armor = armor };
|
||||
for (int slot = 0; slot < 4; slot++)
|
||||
{
|
||||
string id = InventoryGrid.EquipmentId(slot, equipment[slot]);
|
||||
if (id == null) return false;
|
||||
var requested = selected?[slot];
|
||||
var item = s.warehouse.Find(part => part.itemId == id && (requested == null || requested == part.uid));
|
||||
if (item == null)
|
||||
{
|
||||
if (requested != null || (!trial && equipment[slot] != 0)) return false;
|
||||
item = new CargoStack(id, 1) { borrowed = true };
|
||||
}
|
||||
else s.warehouse.Remove(item);
|
||||
s.run.installed.Add(item);
|
||||
}
|
||||
s.sorties++;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public bool AddCargo(string id, int count, string sourceKey = "")
|
||||
{
|
||||
if (count <= 0)
|
||||
return false;
|
||||
return Commit(s =>
|
||||
{
|
||||
if (!s.run.active)
|
||||
return false;
|
||||
if (sourceKey.Length > 0 && s.run.searched.Contains(sourceKey))
|
||||
return false;
|
||||
foreach (var stack in s.run.cargo)
|
||||
{
|
||||
if (id.StartsWith("blueprint_") || stack.itemId != id || stack.count + count > 10)
|
||||
continue;
|
||||
stack.count += count;
|
||||
if (sourceKey.Length > 0)
|
||||
s.run.searched.Add(sourceKey);
|
||||
return true;
|
||||
}
|
||||
if (s.run.cargo.Count >= 4 || (id.StartsWith("blueprint_") ? count != 1 : count > 10))
|
||||
return false;
|
||||
s.run.cargo.Add(new CargoStack(id, count));
|
||||
if (sourceKey.Length > 0)
|
||||
s.run.searched.Add(sourceKey);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
static void Bank(GameSave s, CargoStack stack)
|
||||
{
|
||||
if (stack.itemId == "alloy")
|
||||
s.alloy += stack.count;
|
||||
else if (stack.itemId == "cells")
|
||||
s.cells += stack.count;
|
||||
else if (!s.blueprints.Contains(stack.itemId))
|
||||
s.blueprints.Add(stack.itemId);
|
||||
else
|
||||
s.alloy += 2;
|
||||
}
|
||||
|
||||
public bool SendCargo(IReadOnlyCollection<string> selection)
|
||||
{
|
||||
if (selection == null || selection.Count == 0 || selection.Count > 2)
|
||||
return false;
|
||||
var ids = new HashSet<string>(selection);
|
||||
if (ids.Count != selection.Count)
|
||||
return false;
|
||||
return Commit(s =>
|
||||
{
|
||||
string receipt = s.run.id + ":cargo";
|
||||
if (!s.run.active || s.run.armor <= 0 || s.run.podUsed || s.receipts.Contains(receipt))
|
||||
return false;
|
||||
var picked = s.run.cargo.FindAll(x => ids.Contains(x.uid));
|
||||
if (picked.Count != ids.Count)
|
||||
return false;
|
||||
foreach (var stack in picked)
|
||||
{
|
||||
Bank(s, stack);
|
||||
s.run.cargo.Remove(stack);
|
||||
}
|
||||
s.run.podUsed = true;
|
||||
s.receipts.Add(receipt);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public bool Finish(bool destroyed)
|
||||
{
|
||||
return Commit(s =>
|
||||
{
|
||||
string receipt = s.run.id + ":return";
|
||||
if (!s.run.active || s.receipts.Contains(receipt))
|
||||
return false;
|
||||
if (!destroyed)
|
||||
{
|
||||
foreach (var stack in s.run.cargo)
|
||||
Bank(s, stack);
|
||||
s.extractions++;
|
||||
}
|
||||
s.run.cargo.Clear();
|
||||
s.run.active = false;
|
||||
s.receipts.Add(receipt);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public bool CompleteRoute()
|
||||
{
|
||||
return Commit(s =>
|
||||
|
||||
Reference in New Issue
Block a user