private void LoadTalk() { if (Sekiro) { Talk = Editor.LoadBnds("Base", (data, path) => ESD.Read(data), "*.talkesdbnd.dcx"); MaybeOverrideFromModDir(Talk, name => $@"script\talk\{name}.talkesdbnd.dcx", path => Editor.LoadBnd(path, (data, path2) => ESD.Read(data))); List <string> missing = Locations.Keys.Concat(new[] { "m00_00_00_00" }).Except(Talk.Keys).ToList(); if (missing.Count != 0) { throw new Exception($@"Missing talkesdbnds in dist\Base: {string.Join(", ", missing)}"); } } }
public PropertyEditor(ESD esd) { currentESD = esd; InitializeComponent(); compressionBox.DataSource = Enum.GetValues(typeof(DCX.Type)).Cast <DCX.Type>().ToList(); compressionBox.SelectedItem = currentESD.Compression; nameBox.Text = currentESD.Name; if (currentESD.DarkSoulsCount == 1) { DS1_Btn.Checked = true; } else if (currentESD.DarkSoulsCount == 2) { DS2BB_Btn.Checked = true; } else if (currentESD.DarkSoulsCount == 3) { DS3_Btn.Checked = true; } }
private void openESDToolStripMenuItem_Click(object sender, EventArgs e) { var ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.OK) { try { activeESD = ESD.Read(ofd.FileName); GUI.ActiveForm.Text = "Zeddit - " + Path.GetFileName(ofd.FileName); foreach (var group in activeESD.StateGroups) { StateGroupBox.Items.Add(group.Key); } } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } }
private ItemLocs FindItemLocs(GameData game) { PARAM itemLots = game.Param("ItemLotParam"); PARAM npcs = game.Param("NpcParam"); ItemLocs ret = new ItemLocs { usedItemLots = new SortedDictionary <int, List <EntityId> >(), usedBaseShops = new SortedDictionary <int, List <EntityId> >(), baseLotsToCreate = new Dictionary <int, int>(), // TODO: See if we can have a reasaonable processing step newEntityLots = new Dictionary <int, int>(), }; Dictionary <EntityId, EntityId> objects = new Dictionary <EntityId, EntityId>(); Dictionary <int, List <EntityId> > usedNpcs = new Dictionary <int, List <EntityId> >(); Dictionary <int, List <EntityId> > usedEntities = new Dictionary <int, List <EntityId> >(); Dictionary <int, List <EntityId> > usedEsds = new Dictionary <int, List <EntityId> >(); // Map from item lot to ESD id, hackily extracted from ESD. Dictionary <int, HashSet <int> > talkItemLocations = new Dictionary <int, HashSet <int> >(); // This is a bit intensive. Ideally just dump this somewhere else HashSet <int> debugEsd = new HashSet <int>(); IEnumerable <ESD.Condition> GetCommands(List <ESD.Condition> condList) => Enumerable.Concat(condList, condList.SelectMany(cond => GetCommands(cond.Subconditions))); foreach (KeyValuePair <string, Dictionary <string, ESD> > entry in game.Talk) { string location = game.Locations.ContainsKey(entry.Key) ? game.Locations[entry.Key] : ""; // 62210 foreach (KeyValuePair <string, ESD> esdEntry in entry.Value) { ESD esd = esdEntry.Value; int esdId = int.Parse(esdEntry.Key.Substring(1)); foreach ((int, int, ESD.State)stateDesc in esd.StateGroups.SelectMany(stateGroup => stateGroup.Value.Select(state => (stateGroup.Key, state.Key, state.Value)))) { (int groupId, int id, ESD.State state) = stateDesc; foreach (ESD.CommandCall cmd in new[] { state.EntryCommands, state.WhileCommands, state.ExitCommands, GetCommands(state.Conditions).SelectMany(c => c.PassCommands) }.SelectMany(c => c)) { foreach (byte[] arg in cmd.Arguments) { if (arg.Length == 6 && arg[0] == 0x82 && arg[5] == 0xA1) { int opt = BitConverter.ToInt32(arg, 1); if (opt >= 60000 && opt <= 69900 && itemLots[opt] != null) { AddMulti(talkItemLocations, opt, esdId); } } } } } } } bool logEntities = false; foreach (KeyValuePair <string, MSBS> entry in game.Smaps) { string location = game.Locations[entry.Key]; MSBS msb = entry.Value; Dictionary <string, int> partEsds = new Dictionary <string, int>(); List <MSBS.Part.Enemy> enemies = msb.Parts.Enemies; // TODO: Update SoulsFormat and migrate to new names foreach (MSBS.Event.Talk ev in entry.Value.Events.Talks) { for (int i = 0; i < 2; i++) { string part = ev.EnemyNames[i]; int esdId = ev.TalkIDs[i]; if (esdId < 0 || part == null) { continue; } partEsds[part] = esdId; } } foreach (MSBS.Entry obj in entry.Value.Parts.GetEntries()) { MSBS.Part part = obj as MSBS.Part; if (part == null) { continue; } EntityId id; int esdId = 0; List <int> groupIDs = part.EntityGroupIDs.Where(groupID => groupID > 0).ToList(); if (part is MSBS.Part.Enemy enemy) { esdId = partEsds.ContainsKey(enemy.Name) ? partEsds[enemy.Name] : -1; id = new EntityId(location, enemy.Name, enemy.EntityID, enemy.NPCParamID, enemy.CharaInitID, groupIDs); } else if (part is MSBS.Part.Object || logEntities) { id = new EntityId(location, part.Name, part.EntityID, GroupIds: groupIDs); } else { continue; } objects[id] = id; if (id.EventEntityID > 0) { AddMulti(usedEntities, id.EventEntityID, id); } foreach (int groupID in groupIDs) { AddMulti(usedEntities, groupID, id); } if (id.NPCParamID > 0) { AddMulti(usedNpcs, id.NPCParamID, id); } if (esdId > 0) { if (debugEsd.Contains(esdId)) { Console.WriteLine($"ESD {esdId} belongs to {game.EntityName(id, true)} in {location}, entity id {id.EventEntityID}"); } AddMulti(usedEsds, esdId, id); } } } if (logEntities) { foreach (KeyValuePair <int, List <EntityId> > entry in usedEntities.OrderBy(e => e.Key)) { Console.WriteLine($"{entry.Key}: {string.Join(", ", entry.Value.Select(e => $"{game.EntityName(e, true)} in {e.MapName}"))}"); } } List <EntityId> unusedEsd = new List <EntityId> { new EntityId("", "Unknown Dialogue") }; foreach (KeyValuePair <int, HashSet <int> > entry in talkItemLocations) { List <EntityId> talkIds; if (addUnused) { talkIds = entry.Value.SelectMany(esd => usedEsds.ContainsKey(esd) ? usedEsds[esd] : unusedEsd).ToList(); } else { talkIds = entry.Value.Where(esd => usedEsds.ContainsKey(esd)).SelectMany(esd => usedEsds[esd]).ToList(); if (talkIds.Count == 0) { continue; } } AddMulti(ret.usedItemLots, entry.Key, talkIds); } foreach (KeyValuePair <int, int> entry in shopEsds) { if (!usedEsds.ContainsKey(entry.Value) && !addUnused) { continue; } AddMulti(ret.usedBaseShops, entry.Key, usedEsds.ContainsKey(entry.Value) ? usedEsds[entry.Value] : unusedEsd); } foreach (KeyValuePair <string, MSBS> entry in game.Smaps) { string location = game.Locations[entry.Key]; foreach (MSBS.Event.Treasure treasure in entry.Value.Events.Treasures) { if (treasure.TreasurePartName != null) { EntityId id = new EntityId(location, treasure.TreasurePartName); if (!objects.ContainsKey(id)) { if (logUnused) { Console.WriteLine($"Missing entity for treasure {treasure.Name} with entity {treasure.TreasurePartName} and lot {treasure.ItemLotID}"); } continue; } AddMulti(ret.usedItemLots, treasure.ItemLotID, objects[id]); } } } foreach (PARAM.Row row in npcs.Rows) { int npcID = (int)row.ID; PARAM.Cell cell = row["ItemLotId1"]; if (cell == null || (int)cell.Value == -1) { continue; } int itemLot = (int)cell.Value; if (itemLots[itemLot] == null) { if (logUnused) { Console.WriteLine($"Invalid NPC lot item for {npcID} with lot {itemLot}"); } continue; } if (!usedNpcs.ContainsKey(npcID)) { if (logUnused) { Console.WriteLine($"Unused NPC: {npcID}"); } if (addUnused) { AddMulti(ret.usedItemLots, itemLot, new EntityId("", "Unused NPC")); } continue; } AddMulti(ret.usedItemLots, itemLot, usedNpcs[npcID]); } foreach (KeyValuePair <int, int> entry in entityItemLots) { int entityId = entry.Key; List <int> itemLot = new List <int> { entry.Value }; if (additionalEntityItemLots.ContainsKey(entityId)) { itemLot.AddRange(additionalEntityItemLots[entityId]); } List <EntityId> id; if (usedEntities.ContainsKey(entityId)) { id = usedEntities[entityId]; } else { Console.WriteLine($"XX Missing entity {entityId} with item lot {String.Join(", ", itemLot)}"); id = new List <EntityId> { new EntityId("", "from entity") }; } foreach (int lot in itemLot) { if (logUnused && (int)itemLots[lot]["getItemFlagId"].Value == -1 && id[0].GetModelID() != 2150) { Console.WriteLine($"Eventless entity drop, not crystal lizard, for {String.Join(", ", id)} item lot {lot}"); } AddMulti(ret.usedItemLots, lot, id); } } Dictionary <int, int> syntheticLotBase = new Dictionary <int, int>(); foreach (KeyValuePair <int, int> entry in treasureCarpDrops) { int entityId = entry.Key; int baseLot = entry.Value; List <EntityId> id; if (usedEntities.ContainsKey(entityId)) { id = usedEntities[entityId]; } else { Console.WriteLine($"XX Missing entity {entityId} with item lot {baseLot}"); id = new List <EntityId> { new EntityId("", "from entity") }; } if (syntheticLotBase.ContainsKey(baseLot)) { syntheticLotBase[baseLot] += 5; } else { syntheticLotBase[baseLot] = baseLot; } int itemLot = syntheticLotBase[baseLot]; ret.baseLotsToCreate[itemLot] = baseLot; // TODO: See if this info can be extracted anywhere else ret.newEntityLots[entityId] = itemLot; AddMulti(ret.usedItemLots, itemLot, id); } foreach (KeyValuePair <int, string> entry in scriptLots) { int itemLot = entry.Key; if ((int)itemLots[itemLot]["getItemFlagId"].Value == -1) { // TODO: Make sure there are all classified... // Console.WriteLine($"XX No event id attached to script event {itemLot}"); } AddMulti(ret.usedItemLots, itemLot, new EntityId(entry.Value, "Scripted")); } foreach (int itemLot in talkLots) { if ((int)itemLots[itemLot]["getItemFlagId"].Value == -1) { Console.WriteLine($"XX No event id attached to talk event {itemLot}"); } AddMulti(ret.usedItemLots, itemLot, new EntityId("", "from talk")); } int lastLot = 0; bool lastConnected = false; foreach (PARAM.Row lot in itemLots.Rows) { int itemLot = (int)lot.ID; bool connected = (byte)lot["LotItemNum1"].Value == 1; if (itemLot == lastLot + 1) { // Don't require groups of item lots to be connected, only the base lot } else if (connected && lastConnected && (itemLot - lastLot) % 10 == 0 && (itemLot - lastLot) <= 40) { // This is also fine.... aaaa. Bell Demon drops. } else { if (!ret.usedItemLots.ContainsKey(itemLot)) { if (logUnused) { Console.WriteLine($"Unconnected item lot {itemLot}: {game.LotName(itemLot)}"); } if (addUnused) { AddMulti(ret.usedItemLots, itemLot, new EntityId("", "unknown")); } } } lastLot = itemLot; lastConnected = connected; } return(ret); }