コード例 #1
0
ファイル: RulesDatabase.cs プロジェクト: roma-p/akadoc
    public static TwoDA GetTable(string name)
    {
        TwoDA t = null;

        if (Get().m_tables.TryGetValue(name, out t))
        {
            return(t);
        }
        else
        {
            return(null);
        }
    }
コード例 #2
0
        public static void Twoda_rando(KPaths paths)
        {
            BIF b = new BIF(Path.Combine(paths.data, "2da.bif"));
            KEY k = new KEY(paths.chitin_backup);

            b.AttachKey(k, "data\\2da.bif");

            var filesInOverride = paths.FilesInOverride.ToList();

            foreach (BIF.VariableResourceEntry VRE in b.VariableResourceTable.Where(x => Globals.Selected2DAs.Keys.Contains(x.ResRef)))
            {
                // Check to see if this table is already in the override directory.
                TwoDA t;
                if (filesInOverride.Any(fi => fi.Name == $"{VRE.ResRef}.2da"))
                {
                    // Modify the existing table.
                    t = new TwoDA(File.ReadAllBytes(filesInOverride.First(fi => fi.Name == $"{VRE.ResRef}.2da").FullName), VRE.ResRef);
                }
                else
                {
                    // Fetch the table from the 2DA BIF file.
                    t = new TwoDA(VRE.EntryData, VRE.ResRef);
                }

                if (!LookupTable.ContainsKey(VRE.ResRef))
                {
                    // Add 2DA to the table.
                    LookupTable.Add(VRE.ResRef, new Dictionary <string, List <Tuple <string, string> > >());
                }

                foreach (string col in Globals.Selected2DAs[VRE.ResRef])
                {
                    if (!LookupTable[VRE.ResRef].ContainsKey(col))
                    {
                        // Add column to the table.
                        LookupTable[VRE.ResRef].Add(col, new List <Tuple <string, string> >());
                    }

                    var old = t.Data[col].ToList();             // Save list of old data.
                    Randomize.FisherYatesShuffle(t.Data[col]);  // Randomize 2DA column data.

                    for (int i = 0; i < old.Count; i++)
                    {
                        // Add old and new data to the table.
                        LookupTable[VRE.ResRef][col].Add(new Tuple <string, string>(old[i], t.Data[col][i]));
                    }
                }

                t.WriteToDirectory(paths.Override); // Write new 2DA data to file.
            }
        }
コード例 #3
0
        public static void Twoda_rando(KPaths paths)
        {
            BIF b = new BIF(Path.Combine(paths.data, "2da.bif"));
            KEY k = new KEY(paths.chitin_backup);

            b.AttachKey(k, "data\\2da.bif");

            foreach (BIF.VariableResourceEntry VRE in b.VariableResourceTable.Where(x => Globals.Selected2DAs.Keys.Contains(x.ResRef)))
            {
                TwoDA t = new TwoDA(VRE.EntryData, VRE.ResRef);

                foreach (string col in Globals.Selected2DAs[VRE.ResRef])
                {
                    Randomize.FisherYatesShuffle(t.Data[col]);
                }

                t.WriteToDirectory(paths.Override);
            }
        }
コード例 #4
0
        public static void other_rando(KPaths paths)
        {
            // NameGen
            if (Properties.Settings.Default.RandomizeNameGen)
            {
                List <string> male_names       = Properties.Settings.Default.FirstnamesM.Cast <string>().Select(x => x.Trim()).Where(x => x.Length > 2).ToList();
                LTR           ltr_male_names   = new LTR(male_names);
                List <string> female_names     = Properties.Settings.Default.FirstnamesF.Cast <string>().Select(x => x.Trim()).Where(x => x.Length > 2).ToList();
                LTR           ltr_female_names = new LTR(female_names);
                List <string> last_names       = Properties.Settings.Default.Lastnames.Cast <string>().Select(x => x.Trim()).Where(x => x.Length > 2).ToList();
                LTR           ltr_last_names   = new LTR(last_names);

                if (male_names.Any())
                {
                    ltr_male_names.WriteToFile(paths.Override + "humanm.ltr");
                }
                if (female_names.Any())
                {
                    ltr_female_names.WriteToFile(paths.Override + "humanf.ltr");
                }
                if (last_names.Any())
                {
                    ltr_last_names.WriteToFile(paths.Override + "humanl.ltr");
                }
            }

            // Polymorph

            // Random NPC Pazaak Decks
            if (Properties.Settings.Default.RandomizePazaakDecks)
            {
                string ops = "+-*";

                BIF b = new BIF(paths.data + "\\2da.bif");
                KEY k = new KEY(paths.chitin_backup);
                b.AttachKey(k, "data\\2da.bif");

                var resource = b.VariableResourceTable.Where(x => x.ResRef == PAZAAKDECKS_RESREF).FirstOrDefault();
                if (resource == null)
                {
                    throw new ArgumentOutOfRangeException($"The ResRef \"{PAZAAKDECKS_RESREF}\" could not be found.");
                }

                TwoDA t = new TwoDA(resource.EntryData, PAZAAKDECKS_RESREF);

                foreach (string c in t.Columns)
                {
                    if (c == DECKNAME_COLUMN)
                    {
                        continue;
                    }

                    // [+-*][1-6]
                    // "" + ops[Randomize.Rng.Next(0, 3)] + Convert.ToString(Randomize.Rng.Next(1, 7));
                    t.Data[c][0] = $"{ops[Randomize.Rng.Next(0, 3)]}{Convert.ToString(Randomize.Rng.Next(1, 7))}";
                    t.Data[c][1] = $"{ops[Randomize.Rng.Next(0, 3)]}{Convert.ToString(Randomize.Rng.Next(1, 7))}";
                    t.Data[c][2] = $"{ops[Randomize.Rng.Next(0, 3)]}{Convert.ToString(Randomize.Rng.Next(1, 7))}";
                    t.Data[c][3] = $"{ops[Randomize.Rng.Next(0, 3)]}{Convert.ToString(Randomize.Rng.Next(1, 7))}";
                }

                t.WriteToDirectory(paths.Override);
            }
        }
コード例 #5
0
        public static void other_rando(KPaths paths)
        {
            // NameGen
            if (Properties.Settings.Default.RandomizeNameGen)
            {
                List <string> male_names       = Properties.Settings.Default.FirstnamesM.Cast <string>().Select(x => x.Trim()).Where(x => x.Length > 2).ToList();
                LTR           ltr_male_names   = new LTR(male_names);
                List <string> female_names     = Properties.Settings.Default.FirstnamesF.Cast <string>().Select(x => x.Trim()).Where(x => x.Length > 2).ToList();
                LTR           ltr_female_names = new LTR(female_names);
                List <string> last_names       = Properties.Settings.Default.Lastnames.Cast <string>().Select(x => x.Trim()).Where(x => x.Length > 2).ToList();
                LTR           ltr_last_names   = new LTR(last_names);

                if (male_names.Any())
                {
                    NameGenLookup.Add(NAME_GEN_MALE, male_names);
                    ltr_male_names.WriteToFile(paths.Override + "humanm.ltr");
                }
                if (female_names.Any())
                {
                    NameGenLookup.Add(NAME_GEN_FEMALE, female_names);
                    ltr_female_names.WriteToFile(paths.Override + "humanf.ltr");
                }
                if (last_names.Any())
                {
                    NameGenLookup.Add(NAME_GEN_LAST, last_names);
                    ltr_last_names.WriteToFile(paths.Override + "humanl.ltr");
                }
            }

            // Polymorph
            if (Properties.Settings.Default.PolymorphMode)
            {
                BIF b = new BIF(paths.data + "templates.bif");
                KEY k = new KEY(paths.chitin);
                b.AttachKey(k, "data\\templates.bif");



                foreach (var res in b.VariableResourceTable.Where(x => x.ResourceType == ResourceType.UTI))
                {
                    GFF g             = new GFF(res.EntryData);
                    int item_basetype = (g.Top_Level.Fields.Where(x => x.Label == "BaseItem").FirstOrDefault() as GFF.INT).Value;
                    //ignore items that can't be equipped in the chest slot
                    if ((item_basetype < 35 || item_basetype > 43) && (item_basetype < 66 || item_basetype > 68) && item_basetype != 85 && item_basetype != 89)
                    {
                        continue;
                    }

                    ushort rando_appearance = 0;
                    while (Globals.BROKEN_CHARS.Contains((int)rando_appearance) || Globals.LARGE_CHARS.Contains((int)rando_appearance))
                    {
                        rando_appearance = (ushort)Randomize.Rng.Next(508);
                    }

                    //STRUCT that gives an item the "disguise" property
                    GFF.STRUCT disguise_prop = new GFF.STRUCT("", 0,
                                                              new List <GFF.FIELD>()
                    {
                        new GFF.BYTE("ChanceAppear", 100),
                        new GFF.BYTE("CostTable", 0),
                        new GFF.WORD("CostValue", 0),
                        new GFF.BYTE("Param1", 255),
                        new GFF.BYTE("Param1Value", 0),
                        new GFF.WORD("PropertyName", 59),          //Disguise property
                        new GFF.WORD("Subtype", rando_appearance), //The random appearance value (same values used in model rando)
                    }
                                                              );

                    //Adds the disguise property to the UTI's property list
                    (g.Top_Level.Fields.Where(x => x.Label == "PropertiesList").FirstOrDefault() as GFF.LIST).Structs.Add(disguise_prop);

                    PolymorphLookupTable.Add(res.ResRef, rando_appearance);

                    g.WriteToFile(paths.Override + res.ResRef + ".uti");
                }
            }

            // Random NPC Pazaak Decks
            if (Properties.Settings.Default.RandomizePazaakDecks)
            {
                string ops = "+-*";

                BIF b = new BIF(paths.data + "2da.bif");
                KEY k = new KEY(paths.chitin_backup);
                b.AttachKey(k, "data\\2da.bif");

                var resource = b.VariableResourceTable.Where(x => x.ResRef == PAZAAKDECKS_RESREF).FirstOrDefault();
                if (resource == null)
                {
                    throw new ArgumentOutOfRangeException($"The ResRef \"{PAZAAKDECKS_RESREF}\" could not be found.");
                }

                TwoDA t = new TwoDA(resource.EntryData, PAZAAKDECKS_RESREF);

                foreach (string c in t.Columns)
                {
                    if (c == DECKNAME_COLUMN)
                    {
                        NpcPazaakLookupTable.Add(c, new List <Tuple <string, string> >()
                        {
                            new Tuple <string, string>(t.Data[c][0], t.Data[c][0]),
                            new Tuple <string, string>(t.Data[c][1], t.Data[c][1]),
                            new Tuple <string, string>(t.Data[c][2], t.Data[c][2]),
                            new Tuple <string, string>(t.Data[c][3], t.Data[c][3]),
                        });
                        continue;
                    }
                    NpcPazaakLookupTable.Add(c, new List <Tuple <string, string> >());

                    // [+-*][1-6]
                    // "" + ops[Randomize.Rng.Next(0, 3)] + Convert.ToString(Randomize.Rng.Next(1, 7));
                    var card0 = $"{ops[Randomize.Rng.Next(0, 3)]}{Convert.ToString(Randomize.Rng.Next(1, 7))}";
                    var card1 = $"{ops[Randomize.Rng.Next(0, 3)]}{Convert.ToString(Randomize.Rng.Next(1, 7))}";
                    var card2 = $"{ops[Randomize.Rng.Next(0, 3)]}{Convert.ToString(Randomize.Rng.Next(1, 7))}";
                    var card3 = $"{ops[Randomize.Rng.Next(0, 3)]}{Convert.ToString(Randomize.Rng.Next(1, 7))}";

                    NpcPazaakLookupTable[c].Add(new Tuple <string, string>(t.Data[c][0], card0));
                    NpcPazaakLookupTable[c].Add(new Tuple <string, string>(t.Data[c][1], card1));
                    NpcPazaakLookupTable[c].Add(new Tuple <string, string>(t.Data[c][2], card2));
                    NpcPazaakLookupTable[c].Add(new Tuple <string, string>(t.Data[c][3], card3));

                    t.Data[c][0] = card0;
                    t.Data[c][1] = card1;
                    t.Data[c][2] = card2;
                    t.Data[c][3] = card3;
                }

                t.WriteToDirectory(paths.Override);
            }

            // Party Rando
            if (Properties.Settings.Default.RandomizePartyMembers)
            {
                BIF b = new BIF(paths.data + "templates.bif");
                KEY k = new KEY(paths.chitin_backup);
                b.AttachKey(k, "data\\templates.bif");

                foreach (var ID in Party_IDs)
                {
                    // Find a creature that isn't this party member
                    var charsList = b.VariableResourceTable.Where(x => x.ResourceType == ResourceType.UTC).ToList();
                    var character = charsList.First(x => x.ResRef == ID.Item2);
                    BIF.VariableResourceEntry resource;
                    GFF g;

                    do
                    {
                        int randoIndex = Randomize.Rng.Next(charsList.Count);
                        resource = charsList[randoIndex];
                        if (resource.ResRef != character.ResRef && !InvalidPartyMembers.Contains(resource.ResRef))
                        {
                            // Potentially valid party member. Check against broken and large characters.
                            g = new GFF(resource.EntryData);
                            var appearance = g.Top_Level.Fields.First(x => x.Label == ModelRando.LBL_APPEARANCE_TYPE) as GFF.WORD;

                            if (!Globals.BROKEN_CHARS.Contains(appearance.Value) && !Globals.LARGE_CHARS.Contains(appearance.Value))
                            {
                                break; // Character is valid.
                            }
                        }

                        // Character is invalid, broken, or large. Skip it.
                        Console.WriteLine($"Skipped invalid party member ({resource.ResRef}) when randomizing {ID.Item2}.");
                    }while (true);

                    PartyLookupTable.Add(ID.Item3, resource.ResRef);

                    GFF    gOld       = new GFF(character.EntryData);
                    ushort portraitId = (gOld.Top_Level.Fields.Where(x => x.Label == "PortraitId").FirstOrDefault() as GFF.WORD)?.Value ?? 0;

                    // Turns creature file into a playable companion replacing the current party member.
                    (g.Top_Level.Fields.Where(x => x.Label == "Conversation").FirstOrDefault() as GFF.ResRef).Reference   = ID.Item1;
                    (g.Top_Level.Fields.Where(x => x.Label == "Tag").FirstOrDefault() as GFF.CExoString).CEString         = ID.Item3;
                    (g.Top_Level.Fields.Where(x => x.Label == "TemplateResRef").FirstOrDefault() as GFF.ResRef).Reference = ID.Item2;
                    (g.Top_Level.Fields.Where(x => x.Label == "NoPermDeath").FirstOrDefault() as GFF.BYTE).Value          = 1;
                    (g.Top_Level.Fields.Where(x => x.Label == "FactionID").FirstOrDefault() as GFF.WORD).Value            = 2;

                    // Give new companion the old companion's portrait.
                    if (g.Top_Level.Fields.Where(x => x.Label == "PortraitId").FirstOrDefault() is GFF.WORD field)
                    {
                        field.Value = portraitId;
                    }

                    // Henchmen script suite.
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptHeartbeat").FirstOrDefault() as GFF.ResRef).Reference  = "k_hen_heartbt01";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptOnNotice").FirstOrDefault() as GFF.ResRef).Reference   = "k_hen_percept01";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptSpellAt").FirstOrDefault() as GFF.ResRef).Reference    = "";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptAttacked").FirstOrDefault() as GFF.ResRef).Reference   = "k_hen_attacked01";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptDamaged").FirstOrDefault() as GFF.ResRef).Reference    = "k_hen_damage01";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptDisturbed").FirstOrDefault() as GFF.ResRef).Reference  = "";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptEndRound").FirstOrDefault() as GFF.ResRef).Reference   = "k_hen_combend01";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptEndDialogu").FirstOrDefault() as GFF.ResRef).Reference = "";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptDialogue").FirstOrDefault() as GFF.ResRef).Reference   = "k_hen_dialogue01";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptSpawn").FirstOrDefault() as GFF.ResRef).Reference      = "k_hen_spawn01";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptRested").FirstOrDefault() as GFF.ResRef).Reference     = "";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptDeath").FirstOrDefault() as GFF.ResRef).Reference      = "";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptOnBlocked").FirstOrDefault() as GFF.ResRef).Reference  = "k_hen_blocked01";
                    (g.Top_Level.Fields.Where(x => x.Label == "ScriptUserDefine").FirstOrDefault() as GFF.ResRef).Reference = "";

                    // Add a Dummy Feat to prevent the feats menu from crashing.
                    (g.Top_Level.Fields.Where(x => x.Label == "FeatList").FirstOrDefault() as GFF.LIST).Structs.Add(new GFF.STRUCT("", 1, new List <GFF.FIELD>()
                    {
                        new GFF.WORD("Feat", 27)
                    }));

                    // If they are a Jedi class, add a Power to prevent powers menu from crashing.
                    var charClassList = g.Top_Level.Fields.First(x => x.Label == "ClassList") as GFF.LIST;
                    foreach (var classStruct in charClassList.Structs)
                    {
                        var charClassValue = (classStruct.Fields.First(x => x.Label == "Class") as GFF.INT).Value;
                        if (charClassValue == 3 ||  // Jedi Guardian
                            charClassValue == 4 ||  // Jedi Consular
                            charClassValue == 5)    // Jedi Sentinel
                        {
                            // Build a power to add to the list.
                            GFF.STRUCT affectMind = new GFF.STRUCT("", 3, new List <GFF.FIELD>()
                            {
                                new GFF.WORD("Spell", 6),
                                new GFF.BYTE("SpellMetaMagic", 0),
                                new GFF.BYTE("SpellFlags", 1),
                            });

                            if (!(classStruct.Fields.FirstOrDefault(x => x.Label == "KnownList0") is GFF.LIST knownList))
                            {
                                // KnownList0 doesn't exist. Create it and add Affect Mind.
                                classStruct.Fields.Add(new GFF.LIST("KnownList0", new List <GFF.STRUCT>()
                                {
                                    affectMind
                                }));
                            }
                            else if (knownList.Structs.Count == 0)
                            {
                                // KnownList0 exists but is empty. Add affect Mind.
                                knownList.Structs.Add(affectMind);
                            }

                            break;
                        }
                    }

                    g.WriteToFile(paths.Override + ID.Item2 + ".utc");
                }
            }
コード例 #6
0
        public static void model_rando(KPaths paths)
        {
            const int MAX_CHAR_INDEX = 509;
            const int MIN_DOOR_INDEX_BROKEN = 13;
            const int MAX_DOOR_INDEX = 65;
            const int MAX_PLAC_INDEX = 232;

            const string CHAR_2DA = "appearance";
            const string DOOR_2DA = "genericdoors";
            const string PLAC_2DA = "placeables";

            const string COL_LABEL = "label";

            LookupTable.Clear();

            BIF bif = new BIF(Path.Combine(paths.data, "2da.bif"));
            KEY key = new KEY(paths.chitin);
            bif.AttachKey(key, "data\\2da.bif");

            var charVRE = bif.VariableResourceTable.Where(x => x.ResRef == CHAR_2DA).FirstOrDefault();
            var doorVRE = bif.VariableResourceTable.Where(x => x.ResRef == DOOR_2DA).FirstOrDefault();
            var placVRE = bif.VariableResourceTable.Where(x => x.ResRef == PLAC_2DA).FirstOrDefault();

            TwoDA char2DA = new TwoDA(charVRE.EntryData, charVRE.ResRef);
            TwoDA door2DA = new TwoDA(doorVRE.EntryData, doorVRE.ResRef);
            TwoDA plac2DA = new TwoDA(placVRE.EntryData, placVRE.ResRef);

            // Check if the floor panel fix is enabled.
            bool isFloorPanelActive = (Properties.Settings.Default.RandomizePlaceModels & 8) > 0;
            var catacombsFile = AREA_UNK_CATACOMBS;

            // Check if modules have been randomized.
            var moduleFiles = paths.FilesInModules.ToList();
          
            if (ModuleRando.LookupTable.Any())
            {
                // If randomized, ensure module files are processed in the same order every time.
                var sortedLookup = ModuleRando.LookupTable.OrderBy(kvp => kvp.Key);
                var newList = new List<FileInfo>();

                foreach (var kvp in sortedLookup)
                {
                    // Find the file that has replaced the catacombs for the floor panel fix.
                    if (kvp.Key == AREA_UNK_CATACOMBS) catacombsFile = kvp.Value;

                    // Add the files to modify to the new list in proper order.
                    var filesToAdd = moduleFiles.Where(fi => fi.Name.Contains(kvp.Value));
                    newList.AddRange(filesToAdd);
                }

                moduleFiles = newList;
            }

            // Loop through each file and randomize the requested model types.
            foreach (FileInfo fi in moduleFiles)
            {
                RIM r = new RIM(fi.FullName);
                LookupTable.Add(fi.Name, new Dictionary<string, Dictionary<string, Tuple<int, string, int, string>>>());

                // Doors
                if ((Properties.Settings.Default.RandomizeDoorModels & 1) > 0)
                {
                    LookupTable[fi.Name].Add(DOOR, new Dictionary<string, Tuple<int, string, int, string>>());

                    foreach (RIM.rFile rf in r.File_Table.Where(x => x.TypeID == (int)ResourceType.UTD))
                    {

                        GFF g = new GFF(rf.File_Data);

                        int randAppear = 0; //The randomly generated Appearance ID

                        //Generate the random appearacne values before ommitting airlock, to create more seed consistancy
                        if ((Properties.Settings.Default.RandomizeDoorModels & 4) > 0) // Broken Doors
                        {
                            randAppear = Randomize.Rng.Next(MIN_DOOR_INDEX_BROKEN, MAX_DOOR_INDEX); // First 12 doors are open so this is easier
                        }
                        else
                        {
                            randAppear = Randomize.Rng.Next(0, MAX_DOOR_INDEX);
                        }

                        // Airlock
                        if ((Properties.Settings.Default.RandomizeDoorModels & 2) > 0 &&
                            (g.Top_Level.Fields.Where(f => f.Label == LBL_LOC_NAME).FirstOrDefault() as GFF.CExoLocString).StringRef == 21080)
                        {
                            continue;
                        }

                        //Get Info from Door2DA for the Spoiler Log
                        var field = g.Top_Level.Fields.Where(f => f.Label == LBL_GENERIC_TYPE).FirstOrDefault() as GFF.BYTE;
                        int id = (int)field.Value;

                        var label_old = door2DA.Data[COL_LABEL][id];
                        var label_new = door2DA.Data[COL_LABEL][randAppear];

                        LookupTable[fi.Name][DOOR].Add(rf.Label, new Tuple<int, string, int, string>(id, label_old, randAppear, label_new));

                        //Change the appearance value
                        (g.Top_Level.Fields.Where(f => f.Label == LBL_GENERIC_TYPE).FirstOrDefault() as GFF.BYTE).Value = (byte)randAppear;

                        rf.File_Data = g.ToRawData();
                    }
                }

                // Placeables
                if ((Properties.Settings.Default.RandomizePlaceModels & 1) > 0)
                {
                    LookupTable[fi.Name].Add(PLACEABLE, new Dictionary<string, Tuple<int, string, int, string>>());

                    // Check if floor panels should be replaced with valid placeables.
                    bool useValidFloorPanels = isFloorPanelActive && fi.Name.Contains(catacombsFile);

                    foreach (RIM.rFile rf in r.File_Table.Where(k => k.TypeID == (int)ResourceType.UTP))
                    {
                        GFF g = new GFF(rf.File_Data);

                        // If this is a broken placeable, skip it.
                        if (Globals.BROKEN_PLACE.Contains((int)(g.Top_Level.Fields.Where(f => f.Label == LBL_APPEARANCE).FirstOrDefault() as GFF.DWORD).Value)) { continue; }

                        int randAppear = 0;

                        // Randomly generate a valid replacement for the "Lights Out" panels.
                        if (useValidFloorPanels && (rf.Label.StartsWith(LABEL_UNK_FLPNL) || rf.Label == LABEL_UNK_RESETPANEL))
                        {
                            randAppear = Globals.PANEL_PLACE[Randomize.Rng.Next(0, Globals.PANEL_PLACE.Count)];
                        }
                        else
                        {
                            // Generate a random appearance for this placeable.
                            bool isBroken = false;
                            bool isLarge = false;

                            do
                            {
                                randAppear = Randomize.Rng.Next(0, MAX_PLAC_INDEX);
                                isBroken = ((Properties.Settings.Default.RandomizePlaceModels & 4) > 0) && Globals.BROKEN_PLACE.Contains(randAppear); // Always Satisfied if Broken omission disbaled
                                isLarge  = ((Properties.Settings.Default.RandomizePlaceModels & 2) > 0) && Globals.LARGE_PLACE.Contains(randAppear);  // Always satisifed if Large omission disabled
                            }
                            while (isBroken || isLarge);
                        }

                        var field = g.Top_Level.Fields.Where(f => f.Label == LBL_APPEARANCE).FirstOrDefault() as GFF.DWORD;
                        int id = (int)field.Value;

                        var label_old = plac2DA.Data[COL_LABEL][id];
                        var label_new = plac2DA.Data[COL_LABEL][randAppear];

                        LookupTable[fi.Name][PLACEABLE].Add(rf.Label, new Tuple<int, string, int, string>(id, label_old, randAppear, label_new));

                        // Change the appearance value.
                        (g.Top_Level.Fields.Where(f => f.Label == LBL_APPEARANCE).FirstOrDefault() as GFF.DWORD).Value = (uint)randAppear;

                        rf.File_Data = g.ToRawData();
                    }
                }

                // Characters
                if ((Properties.Settings.Default.RandomizeCharModels & 1) > 0)
                {
                    LookupTable[fi.Name].Add(CHARACTER, new Dictionary<string, Tuple<int, string, int, string>>());

                    foreach (RIM.rFile rf in r.File_Table.Where(k => k.TypeID == (int)ResourceType.UTC))
                    {
                        GFF g = new GFF(rf.File_Data);

                        int randAppear = 0;
                        bool isBroken = false;
                        bool isLarge = false;

                        do
                        {
                            randAppear = Randomize.Rng.Next(0, MAX_CHAR_INDEX);
                            isBroken = ((Properties.Settings.Default.RandomizeCharModels & 4) > 0) && Globals.BROKEN_CHARS.Contains(randAppear);  // Always Satisfied if Broken omission disabled
                            isLarge  = ((Properties.Settings.Default.RandomizeCharModels & 2) > 0) && Globals.LARGE_CHARS.Contains(randAppear);   // Always satisifed if Large omission disabled
                        }
                        while (isBroken || isLarge);

                        var field = g.Top_Level.Fields.Where(f => f.Label == LBL_APPEARANCE_TYPE).FirstOrDefault() as GFF.WORD;
                        int id = (int)field.Value;

                        var label_old = char2DA.Data[COL_LABEL][id];
                        var label_new = char2DA.Data[COL_LABEL][randAppear];

                        LookupTable[fi.Name][CHARACTER].Add(rf.Label, new Tuple<int, string, int, string>(id, label_old, randAppear, label_new));

                        (g.Top_Level.Fields.Where(f => f.Label == LBL_APPEARANCE_TYPE).FirstOrDefault() as GFF.WORD).Value = (ushort)randAppear;

                        rf.File_Data = g.ToRawData();
                    }
                }

                r.WriteToFile(fi.FullName);
            }
        }