/// <summary>
    /// Draws and responds to a toggle box for a component type. Clears Special types, if set.
    /// </summary>
    private void DrawToggle(int poolIndex, KMComponentPool.ComponentTypeEnum typeToToggle)
    {
        KMMission       mission       = (KMMission)serializedObject.targetObject;
        KMComponentPool componentPool = mission.GeneratorSetting.ComponentPools[poolIndex];

        bool previousValue = componentPool.ComponentTypes.Contains(typeToToggle);

        if (EditorGUILayout.ToggleLeft(
                typeToToggle.ToString(),
                previousValue))
        {
            if (!componentPool.ComponentTypes.Contains(typeToToggle))
            {
                componentPool.ComponentTypes.Add(typeToToggle);
            }
        }
        else
        {
            componentPool.ComponentTypes.RemoveAll(x => x == typeToToggle);
        }

        //If we just toggled something, clear any special flags too
        bool currentValue = componentPool.ComponentTypes.Contains(typeToToggle);

        if (previousValue != currentValue)
        {
            componentPool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.None;
        }
    }
Example #2
0
    private object CreateMission(CustomMission mission)
    {
        KMMission template = (KMMission)ScriptableObject.CreateInstance(typeof(KMMission));

        template.name                = mission.ID;
        template.DisplayName         = mission.Name;
        template.PacingEventsEnabled = mission.PacingEvents;

        KMGeneratorSetting generator = new KMGeneratorSetting();

        generator.FrontFaceOnly             = mission.FrontFaceOnly;
        generator.NumStrikes                = mission.Strikes;
        generator.TimeLimit                 = mission.TimeLimit;
        generator.TimeBeforeNeedyActivation = mission.TimeBeforeNeedyActivation;

        foreach (var pool in mission.ComponentPools)
        {
            KMComponentPool componentpool = ConvertPool(mission, pool);

            generator.ComponentPools.Add(componentpool);
        }

        template.GeneratorSetting = generator;

        var type     = FindType("ModMission");
        var instance = ScriptableObject.CreateInstance(type);
        var InstType = instance.GetType();

        InstType.GetMethod("ConfigureFrom", @public).Invoke(instance, new object[] { template, "MissionMaker" });
        InstType.GetProperty("name", @public).SetValue(instance, mission.ID, null);

        //InstType.GetProperty("INVALID_MISSION_ID", BindingFlags.Public | BindingFlags.Static).SetValue(instance, mission.ID, null); // This should block out any kind of records being set for these custom missions.

        return(instance);
    }
Example #3
0
 private static bool SamePool(this KMComponentPool a, KMComponentPool b)
 {
     return(a.Count == b.Count &&
            a.AllowedSources == b.AllowedSources &&
            a.SpecialComponentType == b.SpecialComponentType &&
            a.ComponentTypes.ListEquals(b.ComponentTypes) &&
            a.ModTypes.ListEquals(b.ModTypes));
 }
    /// <summary>
    /// Draw the array of mod module names to be selected from.
    /// </summary>
    /// <param name="poolIndex"></param>
    protected void DrawModTypesList(int poolIndex)
    {
        KMMission          mission        = (KMMission)serializedObject.targetObject;
        KMComponentPool    componentPool  = mission.GeneratorSetting.ComponentPools[poolIndex];
        SerializedProperty componentPools = serializedObject.FindProperty("GeneratorSetting.ComponentPools");

        var element = componentPools.GetArrayElementAtIndex(poolIndex);

        EditorGUILayout.PropertyField(element.FindPropertyRelative("ModTypes"), true);

        //Clear any special flags if needed
        if (componentPool.ModTypes != null && componentPool.ModTypes.Count > 0)
        {
            componentPool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.None;
        }
    }
    /// <summary>
    /// Draws and responds to an enum picker for a special component type. Clears regular and special types, if set.
    /// </summary>
    private void DrawSpecialPicker(int poolIndex)
    {
        KMMission       mission       = (KMMission)serializedObject.targetObject;
        KMComponentPool componentPool = mission.GeneratorSetting.ComponentPools[poolIndex];

        KMComponentPool.SpecialComponentTypeEnum previousValue = componentPool.SpecialComponentType;

        componentPool.SpecialComponentType = (KMComponentPool.SpecialComponentTypeEnum)EditorGUILayout.EnumPopup(
            "Type:",
            componentPool.SpecialComponentType, GUILayout.MinWidth(400));

        //If we just changed the special type, clear any component types too
        KMComponentPool.SpecialComponentTypeEnum currentValue = componentPool.SpecialComponentType;
        if (previousValue != currentValue)
        {
            componentPool.ComponentTypes.Clear();
            componentPool.ModTypes.Clear();
        }
    }
    /// <summary>
    /// Draws and responds to a picker for a component sources.
    /// </summary>
    private void DrawComponentSourcePicker(int poolIndex)
    {
        string[] options = new string[] { "Base", "Mods", "Base and Mods" };

        KMMission       mission       = (KMMission)serializedObject.targetObject;
        KMComponentPool componentPool = mission.GeneratorSetting.ComponentPools[poolIndex];

        KMComponentPool.ComponentSource previousValue = componentPool.AllowedSources;

        bool allowBase = (previousValue & KMComponentPool.ComponentSource.Base) == KMComponentPool.ComponentSource.Base;
        bool allowMods = (previousValue & KMComponentPool.ComponentSource.Mods) == KMComponentPool.ComponentSource.Mods;

        int index = 0;

        if (allowBase)
        {
            if (allowMods)
            {
                index = 2;
            }
            else
            {
                index = 0;
            }
        }
        else
        {
            index = 1;
        }

        index = EditorGUILayout.Popup("Source:", index, options, GUILayout.MinWidth(400));

        switch (index)
        {
        case 0: { componentPool.AllowedSources = KMComponentPool.ComponentSource.Base; } break;

        case 1: { componentPool.AllowedSources = KMComponentPool.ComponentSource.Mods; } break;

        case 2: { componentPool.AllowedSources = KMComponentPool.ComponentSource.Base | KMComponentPool.ComponentSource.Mods; } break;
        }
    }
    /// <summary>
    /// Draw the array of mod module names to be selected from.
    /// </summary>
    /// <param name="poolIndex"></param>
    protected void DrawModTypesList(int poolIndex)
    {
        KMMission          mission        = (KMMission)serializedObject.targetObject;
        KMComponentPool    componentPool  = mission.GeneratorSetting.ComponentPools[poolIndex];
        SerializedProperty componentPools = serializedObject.FindProperty("GeneratorSetting.ComponentPools");

        var modTypesElement = componentPools.GetArrayElementAtIndex(poolIndex).FindPropertyRelative("ModTypes");

        EditorGUILayout.PropertyField(modTypesElement, true);

        // Trim whitespace from mod types
        for (int i = 0; i < modTypesElement.arraySize; i++)
        {
            modTypesElement.GetArrayElementAtIndex(i).stringValue = modTypesElement.GetArrayElementAtIndex(i).stringValue.Trim();
        }

        //Clear any special flags if needed
        if (componentPool.ModTypes != null && componentPool.ModTypes.Count > 0)
        {
            componentPool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.None;
        }
    }
Example #8
0
    List <KMComponentPool> BuildComponentPools()
    {
        List <KMComponentPool> pools = new List <KMComponentPool>();

        KMComponentPool solvablePool = new KMComponentPool();

        solvablePool.ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>();
        solvablePool.ModTypes       = new List <string>();

        KMComponentPool needyPool = new KMComponentPool();

        needyPool.ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>();
        needyPool.ModTypes       = new List <string>();

        foreach (KMGameInfo.KMModuleInfo moduleInfo in availableModules)
        {
            if (!disabledModuleIds.Contains(moduleInfo.ModuleId))
            {
                KMComponentPool pool = moduleInfo.IsNeedy ? needyPool : solvablePool;
                if (moduleInfo.IsMod)
                {
                    pool.ModTypes.Add(moduleInfo.ModuleId);
                }
                else
                {
                    pool.ComponentTypes.Add(moduleInfo.ModuleType);
                }
            }
        }
        solvablePool.Count = needyPool.ComponentTypes.Count + needyPool.ModTypes.Count > 0 ? modules - 1 : modules;
        needyPool.Count    = needyPool.ComponentTypes.Count + needyPool.ModTypes.Count > 0 ? 1 : 0;

        pools.Add(solvablePool);
        pools.Add(needyPool);

        return(pools);
    }
    /// <summary>
    /// Draws a label summarizing the component types selected, or a warning if none are.
    /// </summary>
    /// <param name="componentFlags"></param>
    private void DrawComponentPoolSummaryLabel(int poolIndex)
    {
        KMMission       mission = (KMMission)serializedObject.targetObject;
        KMComponentPool pool    = mission.GeneratorSetting.ComponentPools[poolIndex];

        string[] nonEmptyModNames = pool.ModTypes.Where(t => !string.IsNullOrEmpty(t)).ToArray();

        if (pool.SpecialComponentType != KMComponentPool.SpecialComponentTypeEnum.None)
        {
            string specialSummary = string.Format("{0} ({1})",
                                                  pool.SpecialComponentType.ToString(),
                                                  pool.AllowedSources.ToString());
            EditorGUILayout.LabelField(specialSummary);
        }
        else if (pool.ComponentTypes.Count > 0 || nonEmptyModNames.Length > 0)
        {
            EditorStyles.label.wordWrap = true;
            string componentTypeNames = String.Join(", ", pool.ComponentTypes.Select(x => x.ToString()).ToArray());

            if (nonEmptyModNames.Length > 0)
            {
                if (componentTypeNames.Length > 0)
                {
                    componentTypeNames += ", ";
                }

                componentTypeNames += String.Join(", ", nonEmptyModNames);
            }

            EditorGUILayout.LabelField(componentTypeNames);
        }
        else
        {
            EditorGUILayout.HelpBox("No component type selected!", MessageType.Error);
        }
    }
Example #10
0
    private static string GetPoolDmgString(KMComponentPool pool)
    {
        string source;

        // Handle special pools
        switch (pool.SpecialComponentType)
        {
        // Normal pool
        case KMComponentPool.SpecialComponentTypeEnum.None:
            var modules = new List <string>(pool.ModTypes);
            if (pool.ComponentTypes != null)
            {
                modules.AddRange(pool.ComponentTypes.Select(vanillaModule => vanillaModule.ToString()));
            }

            source = modules.Select(s => s.IndexOfAny(new[] { ',', ' ', '+' }) != -1 ? '"' + s + '"' : s).Join(",");
            break;

        // Needy pool
        case KMComponentPool.SpecialComponentTypeEnum.ALL_NEEDY:
            if ((pool.AllowedSources & KMComponentPool.ComponentSource.Base &
                 KMComponentPool.ComponentSource.Mods) != 0)
            {
                source = "ALL_NEEDY";
            }
            else if ((pool.AllowedSources & KMComponentPool.ComponentSource.Mods) != 0 &&
                     (pool.AllowedSources & KMComponentPool.ComponentSource.Base) == 0)
            {
                source = "ALL_MODS_NEEDY";
            }
            else
            {
                source = "ALL_VANILLA_NEEDY";
            }

            break;

        // Solvable pool
        case KMComponentPool.SpecialComponentTypeEnum.ALL_SOLVABLE:
            if ((pool.AllowedSources & KMComponentPool.ComponentSource.Base &
                 KMComponentPool.ComponentSource.Mods) != 0)
            {
                source = "ALL_SOLVABLE";
            }
            else if ((pool.AllowedSources & KMComponentPool.ComponentSource.Mods) != 0 &&
                     (pool.AllowedSources & KMComponentPool.ComponentSource.Base) == 0)
            {
                source = "ALL_MODS";
            }
            else
            {
                source = "ALL_VANILLA";
            }

            break;

        default:
            return(null);
        }

        // Create pool string
        return(pool.Count == 1 ? source : string.Format("{0}*{1}", pool.Count, source));
    }
Example #11
0
    public static KMMission CreateMissionFromDmgString(string dmgString)
    {
        string errorMessage = null;

        // Parse the DMG string
        var matches = TokenRegex.Matches(ContinuationRegex.Replace(dmgString, ""));

        if (matches.Count == 0)
        {
            throw new ParseException("invalid DMG string provided");
        }

        // Bomb settings
        KMGeneratorSetting        currentBomb = null;
        List <KMGeneratorSetting> bombs       = null;

        // Flags
        var bombRepeatCount               = 0;
        int?defaultTime                   = null,
           defaultStrikes                 = null,
           defaultNeedyActivationTime     = null,
           defaultWidgetCount             = null;
        var  defaultFrontOnly             = false;
        bool timeSpecified                = false,
             strikesSpecified             = false,
             needyActivationTimeSpecified = false,
             widgetCountSpecified         = false,
             missionNameSpecified         = false;
        int?factoryMode                   = null;

        // Mission setup
        var mission = ScriptableObject.CreateInstance <KMMission>();

        mission.PacingEventsEnabled = true;
        var pools = new List <KMComponentPool>();
        var missionDescription = "";

        // New bomb handler
        NewBombDelegate newBomb = delegate
        {
            currentBomb = new KMGeneratorSetting {
                FrontFaceOnly = defaultFrontOnly
            };
            timeSpecified            = strikesSpecified = needyActivationTimeSpecified =
                widgetCountSpecified = false;
            pools = new List <KMComponentPool>();
        };

        // Bomb validation handler
        ValidateBombDelegate validateBomb = delegate
        {
            // Load the pools and setup default generator settings
            currentBomb.ComponentPools = pools;
            if (!timeSpecified)
            {
                currentBomb.TimeLimit = defaultTime ?? currentBomb.GetComponentCount() * 120;
            }
            if (!strikesSpecified)
            {
                currentBomb.NumStrikes = defaultStrikes ?? Math.Max(3, currentBomb.GetComponentCount() / 12);
            }
            if (!needyActivationTimeSpecified && defaultNeedyActivationTime.HasValue)
            {
                currentBomb.TimeBeforeNeedyActivation = defaultNeedyActivationTime.Value;
            }
            if (!widgetCountSpecified && defaultWidgetCount.HasValue)
            {
                currentBomb.OptionalWidgetCount = defaultWidgetCount.Value;
            }
        };

        // Deal with each token
        foreach (Match match in matches)
        {
            // Inline mission name
            if (match.Groups["MissionName"].Success)
            {
                if (missionNameSpecified)
                {
                    errorMessage = "mission name specified multiple times";
                    goto error;
                }

                missionNameSpecified = true;

                mission.DisplayName = match.Groups["MissionName"].Value.Trim();
            }
            // Inline description
            else if (match.Groups["DescriptionLine"].Success)
            {
                missionDescription += match.Groups["DescriptionLine"].Value.Trim() + "\n";

                mission.Description = missionDescription.Trim();
            }
            // Multiline name + description
            else if (match.Groups["MissionName2"].Success && match.Groups["Description"].Success)
            {
                if (missionNameSpecified)
                {
                    errorMessage = "mission name specified multiple times";
                    goto error;
                }

                missionNameSpecified = true;

                mission.DisplayName = match.Groups["MissionName2"].Value.Trim();
                mission.Description =
                    match.Groups["Description"].Value.Split('\n').Select(line => line.Trim()).Join("\n");
            }
            // Timer
            else if (match.Groups["Time1"].Success)
            {
                if (timeSpecified)
                {
                    errorMessage = "time specified multiple times";
                    goto error;
                }

                timeSpecified = true;

                // Parse time
                var time = match.Groups["Time3"].Success
                    ? int.Parse(match.Groups["Time1"].Value) * 3600 + int.Parse(match.Groups["Time2"].Value) * 60 +
                           int.Parse(match.Groups["Time3"].Value)
                    : int.Parse(match.Groups["Time1"].Value) * 60 + int.Parse(match.Groups["Time2"].Value);
                if (time <= 0)
                {
                    errorMessage = "invalid time limit";
                    goto error;
                }

                if (currentBomb != null)
                {
                    currentBomb.TimeLimit = time;
                }
                else
                {
                    defaultTime = time;
                }
            }
            // Strike count
            else if (match.Groups["Strikes"].Success || match.Groups["Setting"].Value
                     .Equals("strikes", StringComparison.InvariantCultureIgnoreCase))
            {
                if (strikesSpecified)
                {
                    errorMessage = ("strikes specified multiple times");
                    goto error;
                }

                strikesSpecified = true;

                var strikes = int.Parse(match.Groups["Strikes"].Success
                    ? match.Groups["Strikes"].Value
                    : match.Groups["Value"].Value);
                if (strikes <= 0)
                {
                    errorMessage = "invalid strike limit";
                    goto error;
                }

                if (currentBomb != null)
                {
                    currentBomb.NumStrikes = strikes;
                }
                else
                {
                    defaultStrikes = strikes;
                }
            }
            // Various settings
            else if (match.Groups["Setting"].Success)
            {
                switch (match.Groups["Setting"].Value.ToLowerInvariant())
                {
                // Needy timer
                case "needyactivationtime":
                    if (needyActivationTimeSpecified)
                    {
                        errorMessage = "needy activation time specified multiple times";
                        goto error;
                    }

                    needyActivationTimeSpecified = true;

                    var needyActivationTime = int.Parse(match.Groups["Value"].Value);
                    if (needyActivationTime < 0)
                    {
                        errorMessage = "invalid needy activation time";
                        goto error;
                    }

                    if (currentBomb != null)
                    {
                        currentBomb.TimeBeforeNeedyActivation = needyActivationTime;
                    }
                    else
                    {
                        defaultNeedyActivationTime = needyActivationTime;
                    }
                    break;

                // Widgets
                case "widgets":
                    if (widgetCountSpecified)
                    {
                        errorMessage = "widget count specified multiple times";
                        goto error;
                    }

                    widgetCountSpecified = true;
                    int widgetCount;
                    if (!int.TryParse(match.Groups["Value"].Value, out widgetCount))
                    {
                        errorMessage = "invalid widget count";
                        goto error;
                    }

                    if (widgetCount < 0)
                    {
                        errorMessage = "invalid widget count";
                        goto error;
                    }

                    if (currentBomb != null)
                    {
                        currentBomb.OptionalWidgetCount = widgetCount;
                    }
                    else
                    {
                        defaultWidgetCount = widgetCount;
                    }
                    break;

                // Front only
                case "frontonly":
                    if (currentBomb != null)
                    {
                        currentBomb.FrontFaceOnly = true;
                    }
                    else
                    {
                        defaultFrontOnly = true;
                    }
                    break;

                // No pacing
                case "nopacing":
                    if (bombs != null && currentBomb != null)
                    {
                        errorMessage = "nopacing cannot be a bomb-level setting";
                        goto error;
                    }
                    else
                    {
                        mission.PacingEventsEnabled = false;
                    }

                    break;

                // Factory mode
                case "factory":
                    if (bombs != null && currentBomb != null)
                    {
                        errorMessage = "Factory mode cannot be a bomb-level setting";
                        goto error;
                    }
                    else if (factoryMode.HasValue)
                    {
                        errorMessage = "factory mode specified multiple times";
                        goto error;
                    }
                    else
                    {
                        int i;
                        for (i = 0; i < FactoryModes.Length; ++i)
                        {
                            if (FactoryModes[i].Equals(match.Groups["Value"].Value,
                                                       StringComparison.InvariantCultureIgnoreCase))
                            {
                                break;
                            }
                        }

                        if (i >= FactoryModes.Length)
                        {
                            errorMessage = "invalid factory mode";
                            goto error;
                        }

                        factoryMode = i;
                    }

                    break;
                }
            }
            // Module pools
            else if (match.Groups["ID"].Success)
            {
                // Break on unmatched quote
                if (match.Groups["Error"].Success)
                {
                    errorMessage = "unclosed quote";
                    goto error;
                }

                // Create a new bomb
                if (bombs == null)
                {
                    if (currentBomb == null)
                    {
                        newBomb();

                        // Setup the bomb
                        if (defaultTime.HasValue)
                        {
                            timeSpecified         = true;
                            currentBomb.TimeLimit = defaultTime.Value;
                        }

                        if (defaultStrikes.HasValue)
                        {
                            strikesSpecified       = true;
                            currentBomb.NumStrikes = defaultStrikes.Value;
                        }

                        if (defaultNeedyActivationTime.HasValue)
                        {
                            needyActivationTimeSpecified          = true;
                            currentBomb.TimeBeforeNeedyActivation = defaultNeedyActivationTime.Value;
                        }

                        if (defaultWidgetCount.HasValue)
                        {
                            widgetCountSpecified            = true;
                            currentBomb.OptionalWidgetCount = defaultWidgetCount.Value;
                        }
                    }
                }
                else
                {
                    if (currentBomb == null)
                    {
                        errorMessage = "Unexpected module pool";
                        goto error;
                    }
                }

                // Create the module pool
                var pool = new KMComponentPool
                {
                    Count          = match.Groups["Count"].Success ? int.Parse(match.Groups["Count"].Value) : 1,
                    ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>(),
                    ModTypes       = new List <string>()
                };
                if (pool.Count <= 0)
                {
                    errorMessage = "Invalid module pool count";
                    goto error;
                }

                // Parse module IDs
                var list = match.Groups["ID"].Value.Replace("\"", "").Replace("'", "").Trim();
                if (list.StartsWith("mode:"))
                {
                    continue;
                }
                switch (list)
                {
                // Module groups
                case "ALL_SOLVABLE":
                    pool.AllowedSources =
                        KMComponentPool.ComponentSource.Base | KMComponentPool.ComponentSource.Mods;
                    pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_SOLVABLE;
                    break;

                case "ALL_NEEDY":
                    pool.AllowedSources =
                        KMComponentPool.ComponentSource.Base | KMComponentPool.ComponentSource.Mods;
                    pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_NEEDY;
                    break;

                case "ALL_VANILLA":
                    pool.AllowedSources       = KMComponentPool.ComponentSource.Base;
                    pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_SOLVABLE;
                    break;

                case "ALL_MODS":
                    pool.AllowedSources       = KMComponentPool.ComponentSource.Mods;
                    pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_SOLVABLE;
                    break;

                case "ALL_VANILLA_NEEDY":
                    pool.AllowedSources       = KMComponentPool.ComponentSource.Base;
                    pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_NEEDY;
                    break;

                case "ALL_MODS_NEEDY":
                    pool.AllowedSources       = KMComponentPool.ComponentSource.Mods;
                    pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_NEEDY;
                    break;

                // Individual module IDs
                default:
                    foreach (var id in list.Split(',', '+').Select(s => s.Trim()))
                    {
                        switch (id)
                        {
                        // Vanilla modules
                        case "WireSequence":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.WireSequence);
                            break;

                        case "Wires":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Wires);
                            break;

                        case "WhosOnFirst":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.WhosOnFirst);
                            break;

                        case "Simon":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Simon);
                            break;

                        case "Password":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Password);
                            break;

                        case "Morse":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Morse);
                            break;

                        case "Memory":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Memory);
                            break;

                        case "Maze":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Maze);
                            break;

                        case "Keypad":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Keypad);
                            break;

                        case "Venn":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Venn);
                            break;

                        case "BigButton":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.BigButton);
                            break;

                        case "NeedyCapacitor":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.NeedyCapacitor);
                            break;

                        case "NeedyVentGas":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.NeedyVentGas);
                            break;

                        case "NeedyKnob":
                            pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.NeedyKnob);
                            break;

                        // Modded modules
                        default:
                            pool.ModTypes.Add(id);
                            break;
                        }
                    }

                    break;
                }

                pools.Add(pool);
            }
            // Multiple Bombs starting point
            else if (match.Groups["Open"].Success)
            {
                if (currentBomb != null)
                {
                    errorMessage = "Unexpected '('";
                    goto error;
                }

                bombRepeatCount = match.Groups["Count"].Success ? int.Parse(match.Groups["Count"].Value) : 1;
                if (bombRepeatCount <= 0)
                {
                    errorMessage = "Invalid bomb repeat count";
                    goto error;
                }

                if (bombs == null)
                {
                    bombs = new List <KMGeneratorSetting>();
                }
                newBomb();
            }
            // Multiple Bombs ending point
            else if (match.Groups["Close"].Success)
            {
                if (currentBomb == null)
                {
                    errorMessage = "Unexpected ')'";
                    goto error;
                }

                validateBomb();
                for (; bombRepeatCount > 0; --bombRepeatCount)
                {
                    bombs.Add(currentBomb);
                }
                currentBomb = null;
            }
        }

        // Check if no modules were provided
        if (bombs == null)
        {
            if (currentBomb == null)
            {
                errorMessage = "No solvable modules";
                goto error;
            }

            validateBomb();
            mission.GeneratorSetting = currentBomb;
        }
        else if (bombs.Count == 0)
        {
            errorMessage = "No solvable modules";
        }

        // Handle parsing error
error:
        if (errorMessage != null)
        {
            Debug.LogErrorFormat("[DMG] Error: {0}", errorMessage);
            throw new ParseException(errorMessage);
        }

        // Convert bombs to JSON for Multiple Bombs
        if (bombs != null)
        {
            mission.GeneratorSetting = bombs[0];
            if (bombs.Count > 1)
            {
                mission.GeneratorSetting.ComponentPools.Add(new KMComponentPool
                {
                    Count    = bombs.Count - 1, ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>(),
                    ModTypes = new List <string> {
                        "Multiple Bombs"
                    }
                });
                for (int i = 1; i < bombs.Count; ++i)
                {
                    // if (bombs[i] != mission.GeneratorSetting)
                    mission.GeneratorSetting.ComponentPools.Add(new KMComponentPool
                    {
                        Count    = 1, ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>(),
                        ModTypes = new List <string>
                        {
                            string.Format("Multiple Bombs:{0}:{1}", i, JsonConvert.SerializeObject(bombs[i]))
                        }
                    });
                }
            }
        }

        // Apply factory mode
        if (factoryMode.HasValue)
        {
            mission.GeneratorSetting.ComponentPools.Add(new KMComponentPool
            {
                Count    = factoryMode.Value, ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>(),
                ModTypes = new List <string> {
                    "Factory Mode"
                }
            });
        }

        return(mission);
    }
Example #12
0
    private KMComponentPool ConvertPool(CustomMission mission, CustomPool pool)
    {
        KMComponentPool componentpool = new KMComponentPool();
        string          Source        = pool.Source;

        // If no source is specified try to figure out what the user wanted.
        if (Source == null)
        {
            if (pool.Modules != null)
            {
                Source = "none";
            }
            else if (pool.Group != null)
            {
                Source = "group";
            }
            else if (pool.Pools != null)
            {
                Source = "pools";
            }
            else
            {
                Log("No source was able to be determined for a pool in the mission located at {0}.", mission.Path);
                return(null);
            }
        }
        else
        {
            Source = Source.ToLowerInvariant();
        }

        if (Source == "group")
        {
            if (pool.Group == null)
            {
                Log("Source was set to Group but no Group parameter found in mission located at {0}.", mission.Path);
                return(null);
            }

            if (Groups.ContainsKey(pool.Group))
            {
                CustomGroup group = Groups[pool.Group];
                pool.Group  = null;
                pool.Source = group.Source;
                pool.Mods   = group.Mods;
                pool.Base   = group.Base;

                if (pool.Blacklist != null)
                {
                    pool.Modules = group.Modules.Except(pool.Blacklist).ToList();
                }
                else
                {
                    pool.Modules = group.Modules;
                }

                Source = pool.Source != null?pool.Source.ToLowerInvariant() : "none";
            }
            else
            {
                Log("Unable to find group {0} for the mission located at {2}.", pool.Group, mission.Path);
            }
        }

        if (Source == "pools")
        {
            if (pool.Pools == null)
            {
                Log("Source was set to Pools but no Pools parameter found in mission located at {0}.", mission.Path);
                return(null);
            }

            componentpool.Count = pool.Count;

            HashSet <string> Modules = new HashSet <string>();
            HashSet <KMComponentPool.ComponentTypeEnum> ComponentTypes = new HashSet <KMComponentPool.ComponentTypeEnum>();
            foreach (CustomPool pool2 in pool.Pools)
            {
                KMComponentPool componentpool2 = ConvertPool(mission, pool2);
                foreach (string module in componentpool2.ModTypes)
                {
                    Modules.Add(module);
                }

                foreach (KMComponentPool.ComponentTypeEnum module in componentpool2.ComponentTypes)
                {
                    ComponentTypes.Add(module);
                }
            }

            componentpool.ModTypes       = Modules.ToList();
            componentpool.ComponentTypes = ComponentTypes.ToList();

            if (ComponentTypes.Count > 0 && !(Modules.Count > 0))
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Base;
            }
            else if (!(ComponentTypes.Count > 0) && Modules.Count > 0)
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Mods;
            }
            else
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Base | KMComponentPool.ComponentSource.Mods;
            }

            componentpool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.None;
        }

        if (Source == "none")
        {
            if (pool.Modules == null)
            {
                Log("Source was set to None but no Modules parameter found in the mission located at {0}.", mission.Path);
                return(null);
            }

            List <string> modded = new List <string>();
            List <KMComponentPool.ComponentTypeEnum> vanilla = new List <KMComponentPool.ComponentTypeEnum>();

            foreach (string module in pool.Modules)
            {
                if (Enum.IsDefined(typeof(KMComponentPool.ComponentTypeEnum), module))
                {
                    if (module != "Empty" && module != "Timer")
                    {
                        vanilla.Add((KMComponentPool.ComponentTypeEnum)Enum.Parse(typeof(KMComponentPool.ComponentTypeEnum), module));
                    }
                }
                else
                {
                    modded.Add(module);
                }
            }

            bool hasModded = modded.Count > 0;
            if (hasModded)
            {
                componentpool.ModTypes = modded;
            }
            bool hasVanilla = vanilla.Count > 0;
            componentpool.ComponentTypes = hasVanilla ? vanilla : new List <KMComponentPool.ComponentTypeEnum>();

            if (hasVanilla && !hasModded)
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Base;
            }
            else if (!hasVanilla && hasModded)
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Mods;
            }
            else
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Base | KMComponentPool.ComponentSource.Mods;
            }

            componentpool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.None;
        }
        else
        {
            if (!pool.Base && !pool.Mods)
            {
                Log("A source besides None was used but has both base and mods disabled in the mission located at {0}. Skipping pool.", mission.Path);
                return(null);
            }

            if (pool.Base && !pool.Mods)
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Base;
            }
            else if (!pool.Base && pool.Mods)
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Mods;
            }
            else
            {
                componentpool.AllowedSources = KMComponentPool.ComponentSource.Base | KMComponentPool.ComponentSource.Mods;
            }
            componentpool.ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>();

            if (Source == "solvable")
            {
                if (pool.Mods)
                {
                    componentpool.ModTypes = new List <string>();
                    foreach (KMBombModule module in GetAllModObjects <KMBombModule>())
                    {
                        if (pool.Blacklist == null || !pool.Blacklist.Contains(module.ModuleType))
                        {
                            componentpool.ModTypes.Add(module.ModuleType);
                        }
                    }
                }

                if (pool.Base)
                {
                    componentpool.ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>();
                    foreach (string name in Enum.GetNames(typeof(KMComponentPool.ComponentTypeEnum)))
                    {
                        if (!name.StartsWith("Needy") && name != "Empty" && name != "Timer" && (pool.Blacklist == null || !pool.Blacklist.Contains(name)))
                        {
                            componentpool.ComponentTypes.Add((KMComponentPool.ComponentTypeEnum)Enum.Parse(typeof(KMComponentPool.ComponentTypeEnum), name));
                        }
                    }
                }
            }
            else if (Source == "needy")
            {
                if (pool.Mods)
                {
                    componentpool.ModTypes = new List <string>();
                    foreach (KMNeedyModule module in GetAllModObjects <KMNeedyModule>())
                    {
                        if (pool.Blacklist == null || !pool.Blacklist.Contains(module.ModuleType))
                        {
                            componentpool.ModTypes.Add(module.ModuleType);
                        }
                    }
                }

                if (pool.Base)
                {
                    componentpool.ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>();
                    foreach (string name in Enum.GetNames(typeof(KMComponentPool.ComponentTypeEnum)))
                    {
                        if (name.StartsWith("Needy") && (pool.Blacklist == null || !pool.Blacklist.Contains(name)))
                        {
                            componentpool.ComponentTypes.Add((KMComponentPool.ComponentTypeEnum)Enum.Parse(typeof(KMComponentPool.ComponentTypeEnum), name));
                        }
                    }
                }
            }
            else
            {
                Log("Unkown source format of {0} was found in the mission located at {1}.", pool.Source, mission.Path);
                return(null);
            }
        }

        componentpool.Count = pool.Count;

        return(componentpool);
    }
Example #13
0
        private bool ParseTextToMission(string text, out KMMission mission, out List <string> messages)
        {
            messages = new List <string>();

            var matches = tokenRegex.Matches(text);

            if (matches.Count == 0 || (matches.Count == 1 && !matches[0].Value.Any(c => !char.IsWhiteSpace(c))) || matches[matches.Count - 1].Index + matches[matches.Count - 1].Length < text.Length)
            {
                messages.Add("Syntax error");
                mission = null;
                return(false);
            }

            bool timeSpecified = false, strikesSpecified = false, anySolvableModules = false;

            mission = ScriptableObject.CreateInstance <KMMission>();
            mission.PacingEventsEnabled = true;
            mission.GeneratorSetting    = new KMGeneratorSetting();
            List <KMComponentPool> pools = new List <KMComponentPool>();

            foreach (Match match in matches)
            {
                if (match.Groups["Min"].Success)
                {
                    if (timeSpecified)
                    {
                        messages.Add("Time specified multiple times");
                    }
                    else
                    {
                        timeSpecified = true;
                        mission.GeneratorSetting.TimeLimit = (match.Groups["Hr"].Success ? int.Parse(match.Groups["Hr"].Value) * 3600 : 0) +
                                                             int.Parse(match.Groups["Min"].Value) * 60 + int.Parse(match.Groups["Sec"].Value);
                        if (mission.GeneratorSetting.TimeLimit <= 0)
                        {
                            messages.Add("Invalid time limit");
                        }
                    }
                }
                else if (match.Groups["Strikes"].Success)
                {
                    if (strikesSpecified)
                    {
                        messages.Add("Strike limit specified multiple times");
                    }
                    else
                    {
                        strikesSpecified = true;
                        mission.GeneratorSetting.NumStrikes = int.Parse(match.Groups["Strikes"].Value);
                        if (mission.GeneratorSetting.NumStrikes <= 0)
                        {
                            messages.Add("Invalid strike limit");
                        }
                    }
                }
                else if (match.Groups["Setting"].Success)
                {
                    switch (match.Groups["Setting"].Value.ToLowerInvariant())
                    {
                    case "strikes":
                        if (match.Groups["Value"].Success)
                        {
                            if (strikesSpecified)
                            {
                                messages.Add("Strike limit specified multiple times");
                            }
                            else
                            {
                                strikesSpecified = true;
                                mission.GeneratorSetting.NumStrikes = int.Parse(match.Groups["Value"].Value);
                                if (mission.GeneratorSetting.NumStrikes <= 0)
                                {
                                    messages.Add("Invalid strike limit");
                                }
                            }
                        }
                        break;

                    case "needyactivationtime":
                        if (match.Groups["Value"].Success)
                        {
                            mission.GeneratorSetting.TimeBeforeNeedyActivation = int.Parse(match.Groups["Value"].Value);
                        }
                        break;

                    case "widgets":
                        if (match.Groups["Value"].Success)
                        {
                            mission.GeneratorSetting.OptionalWidgetCount = int.Parse(match.Groups["Value"].Value);
                        }
                        break;

                    case "nopacing": mission.PacingEventsEnabled = false; break;

                    case "frontonly": mission.GeneratorSetting.FrontFaceOnly = true; break;
                    }
                }
                else if (match.Groups["ID"].Success)
                {
                    KMComponentPool pool = new KMComponentPool
                    {
                        Count          = match.Groups["Count"].Success ? int.Parse(match.Groups["Count"].Value) : 1,
                        ComponentTypes = new List <KMComponentPool.ComponentTypeEnum>(),
                        ModTypes       = new List <string>()
                    };
                    if (pool.Count <= 0)
                    {
                        messages.Add("Invalid module pool count");
                    }

                    bool   allSolvable = true;
                    string list        = match.Groups["ID"].Value.Replace("\"", "").Trim();
                    switch (list)
                    {
                    case "ALL_SOLVABLE":
                        anySolvableModules        = true;
                        pool.AllowedSources       = KMComponentPool.ComponentSource.Base | KMComponentPool.ComponentSource.Mods;
                        pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_SOLVABLE;
                        break;

                    case "ALL_NEEDY":
                        pool.AllowedSources       = KMComponentPool.ComponentSource.Base | KMComponentPool.ComponentSource.Mods;
                        pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_NEEDY;
                        break;

                    case "ALL_VANILLA":
                        anySolvableModules        = true;
                        pool.AllowedSources       = KMComponentPool.ComponentSource.Base;
                        pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_SOLVABLE;
                        break;

                    case "ALL_MODS":
                        anySolvableModules        = true;
                        pool.AllowedSources       = KMComponentPool.ComponentSource.Mods;
                        pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_SOLVABLE;
                        break;

                    case "ALL_VANILLA_NEEDY":
                        pool.AllowedSources       = KMComponentPool.ComponentSource.Base;
                        pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_NEEDY;
                        break;

                    case "ALL_MODS_NEEDY":
                        pool.AllowedSources       = KMComponentPool.ComponentSource.Mods;
                        pool.SpecialComponentType = KMComponentPool.SpecialComponentTypeEnum.ALL_NEEDY;
                        break;

                    default:
                        foreach (string id in list.Split(',', '+').Select(s => s.Trim()))
                        {
                            switch (id)
                            {
                            case "WireSequence": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.WireSequence); break;

                            case "Wires": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Wires); break;

                            case "WhosOnFirst": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.WhosOnFirst); break;

                            case "Simon": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Simon); break;

                            case "Password": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Password); break;

                            case "Morse": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Morse); break;

                            case "Memory": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Memory); break;

                            case "Maze": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Maze); break;

                            case "Keypad": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Keypad); break;

                            case "Venn": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.Venn); break;

                            case "BigButton": pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.BigButton); break;

                            case "NeedyCapacitor":
                                allSolvable = false;
                                pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.NeedyCapacitor);
                                break;

                            case "NeedyVentGas":
                                allSolvable = false;
                                pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.NeedyVentGas);
                                break;

                            case "NeedyKnob":
                                allSolvable = false;
                                pool.ComponentTypes.Add(KMComponentPool.ComponentTypeEnum.NeedyKnob);
                                break;

                            default:
                                if (!((IEnumerable <string>)DynamicMissionGenerator.ModSelectorApi["AllSolvableModules"]).Contains(id) &&
                                    !((IEnumerable <string>)DynamicMissionGenerator.ModSelectorApi["AllNeedyModules"]).Contains(id))
                                {
                                    messages.Add($"'{id}' is an unknown module ID.");
                                }
                                else if (((IEnumerable <string>)DynamicMissionGenerator.ModSelectorApi["DisabledSolvableModules"]).Contains(id) ||
                                         ((IEnumerable <string>)DynamicMissionGenerator.ModSelectorApi["DisabledNeedyModules"]).Contains(id))
                                {
                                    messages.Add($"'{id}' is disabled.");
                                }
                                else
                                {
                                    if (((IEnumerable <string>)DynamicMissionGenerator.ModSelectorApi["AllNeedyModules"]).Contains(id))
                                    {
                                        allSolvable = false;
                                    }
                                    pool.ModTypes.Add(id);
                                }
                                break;
                            }
                        }
                        break;
                    }
                    if (allSolvable)
                    {
                        anySolvableModules = true;
                    }
                    if (pool.ModTypes.Count == 0)
                    {
                        pool.ModTypes = null;
                    }
                    if (pool.ComponentTypes.Count == 0)
                    {
                        pool.ComponentTypes = null;
                    }
                    pools.Add(pool);
                }
            }

            if (!anySolvableModules)
            {
                messages.Add("No regular modules");
            }
            mission.GeneratorSetting.ComponentPools = pools;
            if (mission.GeneratorSetting.GetComponentCount() > GetMaxModules())
            {
                messages.Add($"Too many modules for any available bomb casing ({mission.GeneratorSetting.GetComponentCount()} specified; {GetMaxModules()} possible).");
            }

            if (messages.Count > 0)
            {
                Destroy(mission);
                mission = null;
                return(false);
            }
            messages            = null;
            mission.DisplayName = "Custom Freeplay";
            if (!timeSpecified)
            {
                mission.GeneratorSetting.TimeLimit = mission.GeneratorSetting.GetComponentCount() * 120;
            }
            if (!strikesSpecified)
            {
                mission.GeneratorSetting.NumStrikes = Math.Max(3, mission.GeneratorSetting.GetComponentCount() / 12);
            }
            return(true);
        }