示例#1
0
 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)}");
         }
     }
 }
示例#2
0
        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;
            }
        }
示例#3
0
        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);
        }