public static IList <(Location, ITile)> ReadSector(ILogger logger, IItemFactory itemFactory, string fileName, string sectorFileContents, ushort xOffset, ushort yOffset, sbyte z) { itemFactory.ThrowIfNull(nameof(itemFactory)); var loadedTilesList = new List <(Location, ITile)>(); var lines = sectorFileContents.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); foreach (var readLine in lines) { var inLine = readLine?.Split(new[] { CommentSymbol }, 2).FirstOrDefault(); // ignore comments and empty lines. if (string.IsNullOrWhiteSpace(inLine)) { continue; } var data = inLine.Split(new[] { SectorSeparator }, 2); if (data.Length != 2) { throw new InvalidDataException($"Malformed line [{inLine}] in sector file: [{fileName}]"); } var tileInfo = data[0].Split(new[] { PositionSeparator }, 2); var tileData = data[1]; var location = new Location { X = (ushort)(xOffset + Convert.ToUInt16(tileInfo[0])), Y = (ushort)(yOffset + Convert.ToUInt16(tileInfo[1])), Z = z, }; // start off with a tile that has no ground in it. ITile newTile = new Tile(location, null); newTile.AddContent(logger, itemFactory, CipFileParser.Parse(tileData)); loadedTilesList.Add((location, newTile)); } // TODO: proper logging. // Console.WriteLine($"Sector file {sectorFileContents.Name}: {loadedTilesList.Count} tiles loaded."); return(loadedTilesList); }
private IList <ITile> ReadSector(string fileName, string sectorFileContents, ushort xOffset, ushort yOffset, sbyte z) { var loadedTilesList = new List <ITile>(); var lines = sectorFileContents.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); foreach (var readLine in lines) { var inLine = readLine?.Split(new[] { CommentSymbol }, 2).FirstOrDefault(); // ignore comments and empty lines. if (string.IsNullOrWhiteSpace(inLine)) { continue; } var data = inLine.Split(new[] { SectorSeparator }, 2); if (data.Length != 2) { throw new InvalidDataException($"Malformed line [{inLine}] in sector file: [{fileName}]"); } var tileInfo = data[0].Split(new[] { PositionSeparator }, 2); var tileData = data[1]; var location = new Location { X = (ushort)(xOffset + Convert.ToUInt16(tileInfo[0])), Y = (ushort)(yOffset + Convert.ToUInt16(tileInfo[1])), Z = z, }; // start off with a tile that has no ground in it. ITile newTile = this.tileFactory.CreateTile(location); this.AddContent(newTile, CipFileParser.Parse(tileData)); loadedTilesList.Add(newTile); } this.logger.LogTrace($"Sector file {fileName}: {loadedTilesList.Count} tiles loaded."); return(loadedTilesList); }
/// <summary> /// Reads a <see cref="IMonsterTypeEntity"/> out of a monster file. /// </summary> /// <param name="monsterFileInfo">The information about the monster file.</param> /// <returns>The <see cref="IMonsterTypeEntity"/> instance.</returns> private IMonsterTypeEntity ReadMonsterFile(FileInfo monsterFileInfo) { monsterFileInfo.ThrowIfNull(nameof(monsterFileInfo)); if (!monsterFileInfo.Exists) { return(null); } var monsterType = new MonsterTypeEntity(); foreach ((string name, string value) in this.ReadInDataTuples(File.ReadLines(monsterFileInfo.FullName), monsterFileInfo.FullName)) { switch (name) { case "racenumber": monsterType.RaceId = Convert.ToUInt16(value); break; case "name": monsterType.Name = value; break; case "article": monsterType.Article = value; break; case "outfit": var(lookTypeId, headColor, bodyColor, legsColor, feetColor) = CipFileParser.ParseMonsterOutfit(value); monsterType.Outfit = new Outfit() { Id = lookTypeId, Head = headColor, Body = bodyColor, Legs = legsColor, Feet = feetColor, }; break; case "corpse": monsterType.Corpse = Convert.ToUInt16(value); break; case "blood": if (Enum.TryParse(value, out BloodType bloodType)) { monsterType.BloodType = bloodType; } break; case "experience": monsterType.BaseExperienceYield = Convert.ToUInt32(value); break; case "summoncost": monsterType.SummonCost = Convert.ToUInt16(value); break; case "fleethreshold": monsterType.HitpointFleeThreshold = Convert.ToUInt16(value); break; case "attack": monsterType.BaseAttack = Convert.ToUInt16(value); break; case "defend": monsterType.BaseDefense = Convert.ToUInt16(value); break; case "armor": monsterType.BaseArmorRating = Convert.ToUInt16(value); break; case "poison": monsterType.SetConditionInfect(ConditionFlag.Posion, Convert.ToUInt16(value)); break; case "losetarget": monsterType.LoseTargetDistance = Convert.ToByte(value); break; case "strategy": monsterType.Strategy = CipFileParser.ParseMonsterStrategy(value); break; case "flags": var parsedElements = CipFileParser.Parse(value); foreach (var element in parsedElements) { if (!element.IsFlag || element.Attributes == null || !element.Attributes.Any()) { continue; } if (Enum.TryParse(element.Attributes.First().Name, out CipCreatureFlag flagMatch)) { if (flagMatch.ToCreatureFlag() is CreatureFlag creatureFlag) { monsterType.SetCreatureFlag(creatureFlag); } } } break; case "skills": var skillParsed = CipFileParser.ParseMonsterSkills(value); foreach (var skill in skillParsed) { if (!Enum.TryParse(skill.Name, ignoreCase: true, out CipMonsterSkillType mSkill)) { continue; } switch (mSkill) { case CipMonsterSkillType.Hitpoints: monsterType.MaxHitpoints = skill.CurrentLevel < 0 ? ushort.MaxValue : (ushort)skill.DefaultLevel; break; case CipMonsterSkillType.GoStrength: monsterType.BaseSpeed = skill.CurrentLevel < 0 ? ushort.MinValue : (ushort)skill.DefaultLevel; break; case CipMonsterSkillType.CarryStrength: monsterType.Capacity = skill.CurrentLevel < 0 ? ushort.MinValue : (ushort)skill.DefaultLevel; break; case CipMonsterSkillType.FistFighting: if (skill.CurrentLevel > 0) { monsterType.SetSkill(SkillType.NoWeapon, skill.CurrentLevel, skill.DefaultLevel, skill.MaximumLevel, skill.TargetCount, skill.CountIncreaseFactor, skill.IncreaserPerLevel); } break; } } break; case "spells": monsterType.SetSpells(CipFileParser.ParseMonsterSpells(value)); break; case "inventory": monsterType.SetInventory(CipFileParser.ParseMonsterInventory(value)); break; case "talk": monsterType.SetPhrases(CipFileParser.ParsePhrases(value)); break; } } monsterType.Lock(); return(monsterType); }
/// <summary> /// Attempts to load the item catalog. /// </summary> /// <returns>The catalog, containing a mapping of loaded id to the item types.</returns> public IDictionary <ushort, IItemType> LoadTypes() { var itemDictionary = new Dictionary <ushort, IItemType>(); var objectsFilePath = Path.Combine(Environment.CurrentDirectory, this.LoaderOptions.FilePath); var current = new ItemType(); foreach (var readLine in File.ReadLines(objectsFilePath)) { if (readLine == null) { continue; } var inLine = readLine.Split(new[] { CommentSymbol }, 2).FirstOrDefault(); // ignore comments and empty lines. if (string.IsNullOrWhiteSpace(inLine)) { // wrap up the current ItemType and add it if it has enough properties set: if (current.TypeId == 0 || string.IsNullOrWhiteSpace(current.Name)) { continue; } current.LockChanges(); itemDictionary.Add(current.TypeId, current); current = new ItemType(); continue; } var data = inLine.Split(new[] { PropertyValueSeparator }, 2); if (data.Length != 2) { throw new InvalidDataException($"Malformed line [{inLine}] in objects file: [{objectsFilePath}]"); } var propName = data[0].ToLower().Trim(); var propData = data[1].Trim(); switch (propName) { case "typeid": current.SetId(Convert.ToUInt16(propData)); break; case "name": current.SetName(propData.Substring(Math.Min(1, propData.Length), Math.Max(0, propData.Length - 2))); break; case "description": current.SetDescription(propData); break; case "flags": foreach (var element in CipFileParser.Parse(propData)) { var flagName = element.Attributes.First().Name; if (Enum.TryParse(flagName, out ItemFlag flagMatch)) { current.SetFlag(flagMatch); continue; } this.Logger.Warning($"Unknown flag [{flagName}] found on item with TypeID [{current.TypeId}]."); } break; case "attributes": foreach (var attrStr in propData.Substring(Math.Min(1, propData.Length), Math.Max(0, propData.Length - 2)).Split(',')) { var attrPair = attrStr.Split('='); if (attrPair.Length != 2) { this.Logger.Error($"Invalid attribute {attrStr}."); continue; } current.SetAttribute(attrPair[0], Convert.ToInt32(attrPair[1])); } break; } } // wrap up the last ItemType and add it if it has enough properties set: if (current.TypeId != 0 && !string.IsNullOrWhiteSpace(current.Name)) { current.LockChanges(); itemDictionary.Add(current.TypeId, current); } return(itemDictionary); }
/// <summary> /// Reads a <see cref="IMonsterType"/> out of a monster file. /// </summary> /// <param name="monsterFileInfo">The information about the monster file.</param> /// <returns>The <see cref="IMonsterType"/> instance.</returns> private IMonsterType ReadMonsterFile(FileInfo monsterFileInfo) { monsterFileInfo.ThrowIfNull(nameof(monsterFileInfo)); if (!monsterFileInfo.Exists) { return(null); } var monsterType = new MonsterType(); foreach ((string name, string value) in this.ReadInDataTuples(File.ReadLines(monsterFileInfo.FullName), monsterFileInfo.FullName)) { switch (name) { case "racenumber": monsterType.SetId(Convert.ToUInt16(value)); break; case "name": monsterType.SetName(value.Trim('\"')); break; case "article": monsterType.SetArticle(value.Trim('\"')); break; case "outfit": monsterType.SetOutfit(value.Trim('(', ')')); break; case "corpse": monsterType.SetCorpse(Convert.ToUInt16(value)); break; case "blood": monsterType.SetBlood(value); break; case "experience": monsterType.SetExperience(Convert.ToUInt32(value)); break; case "summoncost": monsterType.SetSummonCost(Convert.ToUInt16(value)); break; case "fleethreshold": monsterType.SetFleeTreshold(Convert.ToUInt16(value)); break; case "attack": monsterType.SetAttack(Convert.ToUInt16(value)); break; case "defend": monsterType.SetDefense(Convert.ToUInt16(value)); break; case "armor": monsterType.SetArmor(Convert.ToUInt16(value)); break; case "poison": monsterType.SetConditionInfect(ConditionFlag.Posion, Convert.ToUInt16(value)); break; case "losetarget": monsterType.SetLoseTarget(Convert.ToByte(value)); break; case "strategy": monsterType.SetStrategy(CipFileParser.ParseMonsterStrategy(value)); break; case "flags": monsterType.SetFlags(CipFileParser.Parse(value)); break; case "skills": monsterType.SetSkills(CipFileParser.ParseMonsterSkills(value)); break; case "spells": monsterType.SetSpells(CipFileParser.ParseMonsterSpells(value)); break; case "inventory": monsterType.SetInventory(CipFileParser.ParseMonsterInventory(value)); break; case "talk": monsterType.SetPhrases(CipFileParser.ParsePhrases(value)); break; } } monsterType.Lock(); return(monsterType); }