Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 5
0
        /// <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);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Performs the conversion of .mon files to .json files.
        /// </summary>
        /// <param name="monDirPath">Optional. The path to the directory containing the .mon files. Defaults to the initialization <see cref="options"/> value if not supplied.</param>
        /// <param name="jsonDirPath">Optional. The path to the directory that will contain the .json files. Defaults to the initialization <see cref="options"/> value if not supplied.</param>
        /// <param name="overwriteFiles">Optional. A value indicating whether to overwrite files at the destination folder. Defaults to the initialization <see cref="options"/> value if not supplied.</param>
        public void Convert(string monDirPath = null, string jsonDirPath = null, bool?overwriteFiles = null)
        {
            this.options.MonsterFilesDirectory = monDirPath ?? this.options.MonsterFilesDirectory;
            this.options.OutputDirectory       = jsonDirPath ?? this.options.OutputDirectory;
            this.options.OverwriteFiles        = overwriteFiles ?? this.options.OverwriteFiles;

            DataAnnotationsValidator.ValidateObjectRecursive(this.options);

            var itemDictionary = this.itemTypesLoader.LoadTypes();

            var monDirectoryInfo  = new DirectoryInfo(monDirPath);
            var jsonDirectoryInfo = new DirectoryInfo(jsonDirPath);

            if (!monDirectoryInfo.Exists)
            {
                throw new ArgumentException($"The specified directory for .mon files: [{monDirectoryInfo.FullName}] does not exist.");
            }

            if (!jsonDirectoryInfo.Exists)
            {
                jsonDirectoryInfo.Create();

                if (!jsonDirectoryInfo.Exists)
                {
                    throw new ArgumentException($"The specified output directory: [{jsonDirectoryInfo.FullName}] does not exist and could not be created.");
                }
            }

            var existingFiles = monDirectoryInfo.GetFiles($"*{MonExtension}");
            var modelMap      = new Dictionary <string, MonsterModel>();
            var raceMap       = new Dictionary <uint, string>();

            // Now that both directories exist, start processing files serially.
            foreach (var monFileInfo in existingFiles)
            {
                var parsedMonsterModel = CipFileParser.ParseMonsterFile(monFileInfo);

                if (parsedMonsterModel == null)
                {
                    continue;
                }

                var targetModel        = parsedMonsterModel.ToSerializableModel();
                var fileNameWithoutExt = monFileInfo.Name.Replace(MonExtension, string.Empty);

                modelMap.Add(fileNameWithoutExt, targetModel);
                raceMap.Add(parsedMonsterModel.RaceId, fileNameWithoutExt);
            }

            // Ammend item names and summon references
            foreach (var convertedModel in modelMap.Values)
            {
                this.AmmendInventoryItemNames(itemDictionary, convertedModel);
                this.AmmendSummonReferences(raceMap, convertedModel);
            }

            // Output converted models
            foreach (var(fileNameWithoutExt, convertedModel) in modelMap)
            {
                var convertedFilePath = Path.Combine(jsonDirectoryInfo.FullName, Path.GetTempFileName());
                var targetFilePath    = $"{Path.Combine(jsonDirectoryInfo.FullName, fileNameWithoutExt)}{JsonExtension}";
                var tempFileSream     = File.Create(convertedFilePath);

                using (var fw = new StreamWriter(tempFileSream))
                {
                    var serializedMonster = JsonConvert.SerializeObject(convertedModel, Formatting.Indented);

                    fw.Write(serializedMonster);
                    fw.Flush();
                    fw.Close();
                }

                File.Move(convertedFilePath, targetFilePath, overwriteFiles ?? false);
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Reads a <see cref="MonsterTypeEntity"/> out of a monster file.
        /// </summary>
        /// <param name="monsterFileInfo">The information about the monster file.</param>
        /// <returns>The <see cref="MonsterTypeEntity"/> instance.</returns>
        private static MonsterTypeEntity ReadMonsterFile(FileInfo monsterFileInfo)
        {
            monsterFileInfo.ThrowIfNull(nameof(monsterFileInfo));

            if (!monsterFileInfo.Exists)
            {
                return(null);
            }

            var parsedMonster = CipFileParser.ParseMonsterFile(monsterFileInfo);

            var monsterType = new MonsterTypeEntity()
            {
                RaceId         = parsedMonster.RaceId.ToString(),
                Name           = parsedMonster.Name,
                Article        = parsedMonster.Article,
                OriginalOutfit = new Outfit()
                {
                    Id   = parsedMonster.Outfit.Id,
                    Head = parsedMonster.Outfit.Head,
                    Body = parsedMonster.Outfit.Body,
                    Legs = parsedMonster.Outfit.Legs,
                    Feet = parsedMonster.Outfit.Feet,
                },
                Corpse                = (ushort)parsedMonster.Corpse,
                BloodType             = parsedMonster.BloodType,
                BaseExperienceYield   = parsedMonster.Experience,
                SummonCost            = parsedMonster.SummonCost,
                HitpointFleeThreshold = parsedMonster.FleeThreshold,
                BaseAttack            = parsedMonster.Attack,
                BaseDefense           = parsedMonster.Defense,
                BaseArmorRating       = parsedMonster.Armor,
                LoseTargetDistance    = parsedMonster.LoseTarget,
                Strategy              = parsedMonster.Strategy,
            };

            foreach (var flag in parsedMonster.Flags)
            {
                if (flag.ToCreatureFlag() is CreatureFlag creatureFlag)
                {
                    monsterType.SetCreatureFlag(creatureFlag);
                }
            }

            foreach (var(skillType, defaultLevel, currentLevel, maximumLevel, targetCount, countIncreaseFactor, increaserPerLevel) in parsedMonster.Skills)
            {
                if (!Enum.TryParse(skillType, ignoreCase: true, out CipMonsterSkillType mSkill))
                {
                    continue;
                }

                switch (mSkill)
                {
                case CipMonsterSkillType.Hitpoints:
                    monsterType.MaxHitpoints = currentLevel < 0 ? ushort.MaxValue : (ushort)defaultLevel;
                    break;

                case CipMonsterSkillType.GoStrength:
                    monsterType.BaseSpeed = currentLevel < 0 ? ushort.MinValue : (ushort)defaultLevel;
                    break;

                case CipMonsterSkillType.CarryStrength:
                    monsterType.Capacity = currentLevel < 0 ? ushort.MinValue : (ushort)defaultLevel;
                    break;

                case CipMonsterSkillType.FistFighting:
                    if (currentLevel > 0)
                    {
                        monsterType.SetSkill(SkillType.NoWeapon, Convert.ToInt32(currentLevel), Convert.ToInt32(defaultLevel), Convert.ToInt32(maximumLevel), targetCount, countIncreaseFactor, increaserPerLevel);
                    }

                    break;
                }
            }

            foreach (var spellRule in parsedMonster.Spells)
            {
                // Not implemented yet.
            }

            monsterType.SetInventory(parsedMonster.Inventory);
            monsterType.SetPhrases(parsedMonster.Phrases);

            return(monsterType);
        }