/// <summary> /// Initiates loading of walls. /// </summary> public void Init() { var wallGlobalsPath = ContentManager.GetPath("objectdata/globals/walls.iff"); WallGlobals = new IffFile(wallGlobalsPath); var buildGlobalsPath = ContentManager.GetPath("objectdata/globals/build.iff"); BuildGlobals = new IffFile(buildGlobalsPath); //todo: centralize? InitGlobals(); ushort wallID = 256; var archives = new string[] { "housedata/walls/walls.far", "housedata/walls2/walls2.far", "housedata/walls3/walls3.far", "housedata/walls4/walls4.far" }; for (var i = 0; i < archives.Length; i++) { var archivePath = ContentManager.GetPath(archives[i]); var archive = new FAR1Archive(archivePath, true); var entries = archive.GetAllEntries(); foreach (var entry in entries) { var iff = new IffFile(); DynamicWallFromID[new string(entry.Key.TakeWhile(x => x != '.').ToArray()).ToLowerInvariant()] = wallID; var bytes = archive.GetEntry(entry); using (var stream = new MemoryStream(bytes)) { iff.Read(stream); } var catStrings = iff.Get <STR>(0); Entries.Add(wallID, new WallReference(this) { ID = wallID, FileName = entry.Key, Name = catStrings.GetString(0), Price = int.Parse(catStrings.GetString(1)), Description = catStrings.GetString(2) }); wallID++; } archive.Close(); } var far1 = new FAR1Provider <IffFile>(ContentManager, new IffCodec(), new Regex(".*/walls.*\\.far")); far1.Init(); Walls = far1; NumWalls = wallID; }
public void Init(Content content) { //load and build catalog ItemsByGUID = new Dictionary<uint, ObjectCatalogItem>(); ItemsByCategory = new List<ObjectCatalogItem>[30]; for (int i = 0; i < 30; i++) ItemsByCategory[i] = new List<ObjectCatalogItem>(); var packingslip = new XmlDocument(); packingslip.Load(content.GetPath("packingslips/catalog.xml")); var objectInfos = packingslip.GetElementsByTagName("P"); foreach (XmlNode objectInfo in objectInfos) { sbyte Category = Convert.ToSByte(objectInfo.Attributes["s"].Value); uint guid = Convert.ToUInt32(objectInfo.Attributes["g"].Value, 16); if (Category < 0) continue; var item = new ObjectCatalogItem() { GUID = guid, Category = Category, Price = Convert.ToUInt32(objectInfo.Attributes["p"].Value), Name = objectInfo.Attributes["n"].Value }; ItemsByCategory[Category].Add(item); ItemsByGUID[guid] = item; } //load and build Content Objects into catalog if (File.Exists(Path.Combine(FSOEnvironment.ContentDir, "Objects/catalog_downloads.xml"))) { var dpackingslip = new XmlDocument(); dpackingslip.Load(Path.Combine(FSOEnvironment.ContentDir, "Objects/catalog_downloads.xml")); var downloadInfos = dpackingslip.GetElementsByTagName("P"); foreach (XmlNode objectInfo in downloadInfos) { sbyte dCategory = Convert.ToSByte(objectInfo.Attributes["s"].Value); uint dguid = Convert.ToUInt32(objectInfo.Attributes["g"].Value, 16); if (dCategory < 0) continue; var ditem = new ObjectCatalogItem() { GUID = dguid, Category = dCategory, Price = Convert.ToUInt32(objectInfo.Attributes["p"].Value), Name = objectInfo.Attributes["n"].Value }; ItemsByCategory[dCategory].Add(ditem); ItemsByGUID[dguid] = ditem; } } }
/// <summary> /// Initializes the audio manager. /// </summary> public void Init() { this.Stations = new List <AudioReference>(); this.StationsById = new Dictionary <uint, AudioReference>(); this.Modes = new List <AudioReference>(); var stationsRegEx = new Regex(@"music/stations/.*\.mp3"); foreach (var file in ContentManager.AllFiles) { if (stationsRegEx.IsMatch(file)) { var reference = new AudioReference { Type = AudioType.RADIO_STATION, FilePath = ContentManager.GetPath(file) }; Stations.Add(reference); var idString = Path.GetFileNameWithoutExtension(file); idString = idString.Substring(idString.LastIndexOf("_") + 1); var id = Convert.ToUInt32(idString, 16); reference.ID = id; StationsById.Add(id, reference); } } TSOAudio = new DBPFFile(ContentManager.GetPath("TSOAudio.dat")); tsov2 = new DBPFFile(ContentManager.GetPath("tsov2.dat")); Stings = new DBPFFile(ContentManager.GetPath("Stings.dat")); EP5Samps = new DBPFFile(ContentManager.GetPath("EP5Samps.dat")); EP2 = new DBPFFile(ContentManager.GetPath("EP2.dat")); Hitlists = new DBPFFile(ContentManager.GetPath("HitListsTemp.dat")); SFXCache = new Dictionary <uint, SoundEffect>(); TracksById = new Dictionary <uint, Track>(); TracksByBackupId = new Dictionary <uint, Track>(); HitlistsById = new Dictionary <uint, Hitlist>(); AddTracksFrom(TSOAudio); //load events _Events = new Dictionary <string, HITEventRegistration>(); var content = ContentManager; var newmain = LoadHitGroup(content.GetPath("sounddata/newmain.hit"), content.GetPath("sounddata/eventlist.txt"), content.GetPath("sounddata/newmain.hsm")); var relationships = LoadHitGroup(content.GetPath("sounddata/relationships.hit"), content.GetPath("sounddata/relationships.evt"), content.GetPath("sounddata/relationships.hsm")); var tsoep5 = LoadHitGroup(content.GetPath("sounddata/tsoep5.hit"), content.GetPath("sounddata/tsoep5.evt"), content.GetPath("sounddata/tsoep5.hsm")); var tsoV2 = LoadHitGroup(content.GetPath("sounddata/tsov2.hit"), content.GetPath("sounddata/tsov2.evt"), null); //tsov2 has no hsm file var tsov3 = LoadHitGroup(content.GetPath("sounddata/tsov3.hit"), content.GetPath("sounddata/tsov3.evt"), content.GetPath("sounddata/tsov3.hsm")); var turkey = LoadHitGroup(content.GetPath("sounddata/turkey.hit"), content.GetPath("sounddata/turkey.evt"), content.GetPath("sounddata/turkey.hsm")); RegisterEvents(newmain); RegisterEvents(relationships); RegisterEvents(tsoep5); RegisterEvents(tsoV2); RegisterEvents(tsov3); RegisterEvents(turkey); }
public void Init() { DirCache = new Dictionary <int, string>(); Cache = new ConcurrentDictionary <int, CityMap>(); var dir = Content.GetPath("cities"); foreach (var map in Directory.GetDirectories(dir)) { var id = int.Parse(Path.GetFileName(map).Replace("city_", "")); DirCache.Add(id, map); } dir = Path.Combine(FSOEnvironment.ContentDir, "Cities/"); foreach (var map in Directory.GetDirectories(dir)) { var id = int.Parse(Path.GetFileName(map).Replace("city_", "")); DirCache.Add(id, map); } }
/// <summary> /// Initializes the audio manager. /// </summary> public void Init() { this.Stations = new List <AudioReference>(); this.StationsById = new Dictionary <uint, AudioReference>(); this.Modes = new List <AudioReference>(); var stationsRegEx = new Regex(@"music/stations/.*\.mp3"); foreach (var file in ContentManager.AllFiles) { if (stationsRegEx.IsMatch(file)) { var reference = new AudioReference { Type = AudioType.RADIO_STATION, FilePath = ContentManager.GetPath(file) }; Stations.Add(reference); var idString = Path.GetFileNameWithoutExtension(file); idString = idString.Substring(idString.LastIndexOf("_") + 1); var id = Convert.ToUInt32(idString, 16); reference.ID = id; StationsById.Add(id, reference); } } TSOAudio = new DBPFFile(ContentManager.GetPath("TSOAudio.dat")); tsov2 = new DBPFFile(ContentManager.GetPath("tsov2.dat")); Stings = new DBPFFile(ContentManager.GetPath("Stings.dat")); EP5Samps = new DBPFFile(ContentManager.GetPath("EP5Samps.dat")); EP2 = new DBPFFile(ContentManager.GetPath("EP2.dat")); Hitlists = new DBPFFile(ContentManager.GetPath("HitListsTemp.dat")); SFXCache = new Dictionary <uint, SoundEffect>(); TracksById = new Dictionary <uint, Track>(); HitlistsById = new Dictionary <uint, Hitlist>(); AddTracksFrom(TSOAudio); }
/// <summary> /// Initiates loading of walls. /// </summary> public void Init() { WallStyleToIndex = WallStyleIDs.ToDictionary(x => x, x => Array.IndexOf(WallStyleIDs, x)); this.Entries = new Dictionary <ushort, WallReference>(); this.ById = new Dictionary <ushort, Wall>(); this.StyleById = new Dictionary <ushort, WallStyle>(); this.WallStyles = new List <WallStyle>(); var wallGlobalsPath = ContentManager.GetPath("objectdata/globals/walls.iff"); WallGlobals = new IffFile(wallGlobalsPath); var buildGlobalsPath = ContentManager.GetPath("objectdata/globals/build.iff"); var buildGlobals = new IffFile(buildGlobalsPath); //todo: centralize? /** Get wall styles from globals file **/ var styleStrs = buildGlobals.Get <STR>(0x81); ushort wallID = 1; for (ushort i = 2; i < 512; i += 2) { var far = WallGlobals.Get <SPR>((ushort)(i)); var medium = WallGlobals.Get <SPR>((ushort)(i + 512)); var near = WallGlobals.Get <SPR>((ushort)(i + 1024)); var fard = WallGlobals.Get <SPR>((ushort)(i + 1)); var mediumd = WallGlobals.Get <SPR>((ushort)(i + 513)); var neard = WallGlobals.Get <SPR>((ushort)(i + 1025)); if (fard == null) { //no walls down, just render exactly the same fard = far; mediumd = medium; neard = near; } string name = null, description = null; int price = -1; int buyIndex = -1; WallStyleToIndex.TryGetValue(wallID, out buyIndex); if (buyIndex != -1) { price = int.Parse(styleStrs.GetString(buyIndex * 3)); name = styleStrs.GetString(buyIndex * 3 + 1); description = styleStrs.GetString(buyIndex * 3 + 2); } this.AddWallStyle(new WallStyle { ID = wallID, WallsUpFar = far, WallsUpMedium = medium, WallsUpNear = near, WallsDownFar = fard, WallsDownMedium = mediumd, WallsDownNear = neard, Price = price, Name = name, Description = description }); wallID++; } DynamicStyleID = 256; //styles loaded from objects start at 256. The objd reference is dynamically altered to reference this new id, //so only refresh wall cache at same time as obj cache! (do this on lot unload) /** Get wall patterns from globals file **/ var wallStrs = buildGlobals.Get <STR>(0x83); wallID = 0; for (ushort i = 0; i < 256; i++) { var far = WallGlobals.Get <SPR>((ushort)(i + 1536)); var medium = WallGlobals.Get <SPR>((ushort)(i + 1536 + 256)); var near = WallGlobals.Get <SPR>((ushort)(i + 1536 + 512)); this.AddWall(new Wall { ID = wallID, Far = far, Medium = medium, Near = near, }); if (i > 0 && i < (wallStrs.Length / 3) + 1) { Entries.Add(wallID, new WallReference(this) { ID = wallID, FileName = "global", Name = wallStrs.GetString((i - 1) * 3 + 1), Price = int.Parse(wallStrs.GetString((i - 1) * 3 + 0)), Description = wallStrs.GetString((i - 1) * 3 + 2) }); } wallID++; } Junctions = new Wall { ID = wallID, Far = WallGlobals.Get <SPR>(4096), Medium = WallGlobals.Get <SPR>(4097), Near = WallGlobals.Get <SPR>(4098), }; wallID = 256; var archives = new string[] { "housedata/walls/walls.far", "housedata/walls2/walls2.far", "housedata/walls3/walls3.far", "housedata/walls4/walls4.far" }; DynamicWallFromID = new Dictionary <string, ushort>(); for (var i = 0; i < archives.Length; i++) { var archivePath = ContentManager.GetPath(archives[i]); var archive = new FAR1Archive(archivePath, true); var entries = archive.GetAllEntries(); foreach (var entry in entries) { var iff = new IffFile(); DynamicWallFromID[new string(entry.Key.TakeWhile(x => x != '.').ToArray()).ToLowerInvariant()] = wallID; var bytes = archive.GetEntry(entry); using (var stream = new MemoryStream(bytes)) { iff.Read(stream); } var catStrings = iff.Get <STR>(0); Entries.Add(wallID, new WallReference(this) { ID = wallID, FileName = entry.Key, Name = catStrings.GetString(0), Price = int.Parse(catStrings.GetString(1)), Description = catStrings.GetString(2) }); wallID++; } archive.Close(); } this.Walls = new FAR1Provider <IffFile>(ContentManager, new IffCodec(), new Regex(".*/walls.*\\.far")); Walls.Init(); NumWalls = wallID; }
public void Init(Content content) { //load and build catalog ItemsByGUID = new Dictionary <uint, ObjectCatalogItem>(); ItemsByCategory = new List <ObjectCatalogItem> [30]; for (int i = 0; i < 30; i++) { ItemsByCategory[i] = new List <ObjectCatalogItem>(); } var packingslip = new XmlDocument(); packingslip.Load(content.GetPath("packingslips/catalog.xml")); var objectInfos = packingslip.GetElementsByTagName("P"); foreach (XmlNode objectInfo in objectInfos) { sbyte Category = Convert.ToSByte(objectInfo.Attributes["s"].Value); uint guid = Convert.ToUInt32(objectInfo.Attributes["g"].Value, 16); if (Category < 0) { continue; } var item = new ObjectCatalogItem() { GUID = guid, Category = Category, Price = Convert.ToUInt32(objectInfo.Attributes["p"].Value), Name = objectInfo.Attributes["n"].Value }; ItemsByCategory[Category].Add(item); ItemsByGUID[guid] = item; } //load and build Content Objects into catalog if (File.Exists(Path.Combine(FSOEnvironment.ContentDir, "Objects/catalog_downloads.xml"))) { var dpackingslip = new XmlDocument(); dpackingslip.Load(Path.Combine(FSOEnvironment.ContentDir, "Objects/catalog_downloads.xml")); var downloadInfos = dpackingslip.GetElementsByTagName("P"); foreach (XmlNode objectInfo in downloadInfos) { sbyte dCategory = Convert.ToSByte(objectInfo.Attributes["s"].Value); uint dguid = Convert.ToUInt32(objectInfo.Attributes["g"].Value, 16); if (dCategory < 0) { continue; } var ditem = new ObjectCatalogItem() { GUID = dguid, Category = dCategory, Price = Convert.ToUInt32(objectInfo.Attributes["p"].Value), Name = objectInfo.Attributes["n"].Value }; ItemsByCategory[dCategory].Add(ditem); ItemsByGUID[dguid] = ditem; } } }
/// <summary> /// Initiates loading of floors. /// </summary> public void Init() { this.Entries = new Dictionary <ushort, FloorReference>(); this.ById = new Dictionary <ushort, Floor>(); this.DynamicFloorFromID = new Dictionary <string, ushort>(); var floorGlobalsPath = ContentManager.GetPath("objectdata/globals/floors.iff"); var floorGlobals = new Files.Formats.IFF.IffFile(floorGlobalsPath); FloorGlobals = floorGlobals; var buildGlobalsPath = ContentManager.GetPath("objectdata/globals/build.iff"); var buildGlobals = new Files.Formats.IFF.IffFile(buildGlobalsPath); //todo: centralize? /** There is a small handful of floors in a global file for some reason **/ ushort floorID = 1; var floorStrs = buildGlobals.Get <STR>(0x83); for (ushort i = 1; i < (floorStrs.Length / 3); i++) { var far = floorGlobals.Get <SPR2>(i); var medium = floorGlobals.Get <SPR2>((ushort)(i + 256)); var near = floorGlobals.Get <SPR2>((ushort)(i + 512)); //2048 is water tile this.AddFloor(new Floor { ID = floorID, Far = far, Medium = medium, Near = near }); Entries.Add(floorID, new FloorReference(this) { ID = floorID, FileName = "global", Name = floorStrs.GetString((i - 1) * 3 + 1), Price = int.Parse(floorStrs.GetString((i - 1) * 3 + 0)), Description = floorStrs.GetString((i - 1) * 3 + 2) }); floorID++; } var waterStrs = buildGlobals.Get <STR>(0x85); //add pools for catalog logic Entries.Add(65535, new FloorReference(this) { ID = 65535, FileName = "global", Price = int.Parse(waterStrs.GetString(0)), Name = waterStrs.GetString(1), Description = waterStrs.GetString(2) }); floorID = 256; var archives = new string[] { "housedata/floors/floors.far", "housedata/floors2/floors2.far", "housedata/floors3/floors3.far", "housedata/floors4/floors4.far" }; for (var i = 0; i < archives.Length; i++) { var archivePath = ContentManager.GetPath(archives[i]); var archive = new FAR1Archive(archivePath, true); var entries = archive.GetAllEntries(); foreach (var entry in entries) { var iff = new Files.Formats.IFF.IffFile(); DynamicFloorFromID[new string(entry.Key.TakeWhile(x => x != '.').ToArray()).ToLowerInvariant()] = floorID; var bytes = archive.GetEntry(entry); using (var stream = new MemoryStream(bytes)) { iff.Read(stream); } var catStrings = iff.Get <STR>(0); Entries.Add(floorID, new FloorReference(this) { ID = floorID, FileName = entry.Key, Name = catStrings.GetString(0), Price = int.Parse(catStrings.GetString(1)), Description = catStrings.GetString(2) }); floorID++; } archive.Close(); } NumFloors = floorID; this.Floors = new FAR1Provider <Files.Formats.IFF.IffFile>(ContentManager, new IffCodec(), new Regex(".*/floors.*\\.far")); Floors.Init(); }
/// <summary> /// Initiates loading of world objects. /// </summary> public void Init(bool withSprites) { WithSprites = withSprites; Iffs = new FAR1Provider <IffFile>(ContentManager, new IffCodec(), "objectdata/objects/objiff.far"); TuningTables = new FAR1Provider <OTFFile>(ContentManager, new OTFCodec(), new Regex(".*/objotf.*\\.far")); Iffs.Init(); TuningTables.Init(); if (withSprites) { Sprites = new FAR1Provider <IffFile>(ContentManager, new IffCodec(), new Regex(".*/objspf.*\\.far")); Sprites.Init(); } /** Load packingslip **/ Entries = new Dictionary <ulong, GameObjectReference>(); Cache = new ConcurrentDictionary <ulong, GameObject>(); var packingslip = new XmlDocument(); packingslip.Load(ContentManager.GetPath("packingslips/objecttable.xml")); var objectInfos = packingslip.GetElementsByTagName("I"); foreach (XmlNode objectInfo in objectInfos) { ulong FileID = Convert.ToUInt32(objectInfo.Attributes["g"].Value, 16); Entries.Add(FileID, new GameObjectReference(this) { ID = FileID, FileName = objectInfo.Attributes["n"].Value, Source = GameObjectSource.Far, Name = objectInfo.Attributes["o"].Value, Group = Convert.ToInt16(objectInfo.Attributes["m"].Value), SubIndex = Convert.ToInt16(objectInfo.Attributes["i"].Value) }); } //init local objects, piff clones string[] paths = Directory.GetFiles("Content/Objects", "*.iff", SearchOption.AllDirectories); for (int i = 0; i < paths.Length; i++) { string entry = paths[i]; string filename = Path.GetFileName(entry); IffFile iffFile = new IffFile(entry); var objs = iffFile.List <OBJD>(); foreach (var obj in objs) { Entries.Add(obj.GUID, new GameObjectReference(this) { ID = obj.GUID, FileName = entry, Source = GameObjectSource.Standalone, Name = obj.ChunkLabel, Group = (short)obj.MasterID, SubIndex = obj.SubIndex }); } } }
/// <summary> /// Initializes the audio manager. /// </summary> public void Init() { if (Initialized) { return; } this.Stations = new List <AudioReference>(); this.StationsById = new Dictionary <uint, AudioReference>(); this.Modes = new List <AudioReference>(); var stationsRegEx = new Regex(@"music/stations/.*\.mp3"); foreach (var file in ContentManager.AllFiles) { if (stationsRegEx.IsMatch(file)) { var reference = new AudioReference { Type = AudioType.RADIO_STATION, FilePath = ContentManager.GetPath(file) }; Stations.Add(reference); var idString = Path.GetFileNameWithoutExtension(file); idString = idString.Substring(idString.LastIndexOf("_") + 1); var id = Convert.ToUInt32(idString, 16); reference.ID = id; StationsById.Add(id, reference); } } TSOAudio = new DBPFFile(ContentManager.GetPath("TSOAudio.dat")); tsov2 = new DBPFFile(ContentManager.GetPath("tsov2.dat")); Stings = new DBPFFile(ContentManager.GetPath("Stings.dat")); EP5Samps = new DBPFFile(ContentManager.GetPath("EP5Samps.dat")); EP2 = new DBPFFile(ContentManager.GetPath("EP2.dat")); Hitlists = new DBPFFile(ContentManager.GetPath("HitListsTemp.dat")); SFXCache = new Dictionary <uint, SoundEffect>(); TracksById = new Dictionary <uint, Track>(); TracksByBackupId = new Dictionary <uint, Track>(); HitlistsById = new Dictionary <uint, Hitlist>(); AddTracksFrom(TSOAudio); //load events _Events = new Dictionary <string, HITEventRegistration>(); var content = ContentManager; var newmain = LoadHitGroup(content.GetPath("sounddata/newmain.hit"), content.GetPath("sounddata/eventlist.txt"), content.GetPath("sounddata/newmain.hsm")); var relationships = LoadHitGroup(content.GetPath("sounddata/relationships.hit"), content.GetPath("sounddata/relationships.evt"), content.GetPath("sounddata/relationships.hsm")); var tsoep5 = LoadHitGroup(content.GetPath("sounddata/tsoep5.hit"), content.GetPath("sounddata/tsoep5.evt"), content.GetPath("sounddata/tsoep5.hsm")); var tsoV2 = LoadHitGroup(content.GetPath("sounddata/tsov2.hit"), content.GetPath("sounddata/tsov2.evt"), null); //tsov2 has no hsm file var tsov3 = LoadHitGroup(content.GetPath("sounddata/tsov3.hit"), content.GetPath("sounddata/tsov3.evt"), content.GetPath("sounddata/tsov3.hsm")); var turkey = LoadHitGroup(content.GetPath("sounddata/turkey.hit"), content.GetPath("sounddata/turkey.evt"), content.GetPath("sounddata/turkey.hsm")); RegisterEvents(newmain); RegisterEvents(relationships); RegisterEvents(tsoep5); RegisterEvents(tsoV2); RegisterEvents(tsov3); RegisterEvents(turkey); //register the .xa files over in the nightclub folders. var files = Directory.GetFiles(content.GetPath("sounddata/nightclubsounds/")); foreach (var file in files) { if (!file.EndsWith(".xa")) { continue; } var split = file.Split('_'); uint id = 0; try { var endSplit = split[split.Length - 1]; id = Convert.ToUInt32("0x" + endSplit.Substring(0, endSplit.Length - 3), 16); } catch { continue; } NightclubSounds[id] = file; } Initialized = true; }
public void Init() { var purchasable = Content.GetPath("packingslips/purchasable.xml"); if (!File.Exists(purchasable)) { return; } var xml = new XmlDocument(); xml.Load(purchasable); foreach (XmlNode child in xml.FirstChild.ChildNodes) { if (!(child is XmlElement)) { continue; } var name = child.Name; var assetId = child.Attributes["assetID"]; var price = child.Attributes["price"]; if (assetId == null || price == null) { continue; } var outfit = new RackOutfit { AssetID = (uint)ulong.Parse(assetId.InnerText.Substring(2), NumberStyles.HexNumber), Price = int.Parse(price.InnerText) }; //Convert to full content id so its consistent with DbAvatar outfit.AssetID = (outfit.AssetID << 32) | 0xd; if (name.EndsWith("Male")) { outfit.Gender = RackOutfitGender.Male; outfit.RackType = GetRackType(name.Substring(0, name.Length - 4)); } else if (name.EndsWith("Female")) { outfit.Gender = RackOutfitGender.Female; outfit.RackType = GetRackType(name.Substring(0, name.Length - 6)); } else if (name.StartsWith("Decor")) { outfit.Gender = RackOutfitGender.Neutral; var type = name.Split('_'); outfit.RackType = GetRackType(type[0] + "_" + type[1]); } else { continue; } if (!Racks.ContainsKey(outfit.RackType)) { Racks.Add(outfit.RackType, new RackOutfits() { Outfits = new List <RackOutfit>(), RackType = outfit.RackType }); } Racks[outfit.RackType].Outfits.Add(outfit); } }