示例#1
0
        public override IEnumerator <RST> Run(Sandbox sb)
        {
            var attribs = sb.AttribManager.TakeAttribs();

            // Skip if chance doesn't fall within range
            if (attribs.Chance < 100 && sb.RNG.NextDouble(0, 100) > attribs.Chance)
            {
                yield break;
            }

            int    next      = -1;
            int    reps      = attribs.RepEach ? _elements.Count : attribs.Repetitions;
            var    block     = new BlockState(reps, attribs);
            double weightSum = _constantWeightSum;

            if (attribs.Start != null)
            {
                yield return(attribs.Start);
            }

            if (_weighted && attribs.Sync == null)
            {
                if (_dynamicWeights != null)
                {
                    foreach (var dw in _dynamicWeights)
                    {
                        sb.AddOutputWriter();
                        yield return(dw.Item2);

                        string strWeight = sb.Return().Main;
                        if (string.IsNullOrEmpty(strWeight))
                        {
                            _weights[dw.Item1] = 0.0;
                        }
                        else if (!Util.ParseDouble(strWeight, out _weights[dw.Item1]))
                        {
                            throw new RantRuntimeException(sb, dw.Item2.Location,
                                                           GetString("err-runtime-invalid-dynamic-weight", strWeight));
                        }

                        weightSum += _weights[dw.Item1];
                    }
                }
            }

            if (attribs.Sync?.Index == 0 && attribs.StartIndex >= 0)
            {
                attribs.Sync.Index = attribs.StartIndex;
            }

            sb.Blocks.Push(block);
            for (int i = 0; i < reps; i++)
            {
                if (i == 0 && attribs.StartIndex >= 0 && attribs.Sync == null)
                {
                    next = attribs.StartIndex > _count ? _count - 1 : attribs.StartIndex;
                }
                else if (_weighted)
                {
                    double choice = sb.RNG.NextDouble(weightSum);
                    for (int j = 0; j < _count; j++)
                    {
                        if (choice < _weights[j])
                        {
                            next = j;
                            break;
                        }
                        choice -= _weights[j];
                    }
                }
                else
                {
                    next = attribs.NextIndex(_count, sb.RNG);
                }

                if (next == -1)
                {
                    break;
                }

                block.Next(next);                // Set next block index

                sb.Blocks.Pop();                 // Don't allow separator to access block state

                // Separator
                if (i > 0 && attribs.Separator != null)
                {
                    if (attribs.IsSeries)
                    {
                        // Check if we're on the last separator in a series
                        if (i == reps - 1)
                        {
                            // Add the oxford comma if specified
                            if (attribs.EndSeparator != null)
                            {
                                if (reps > 2)
                                {
                                    yield return(attribs.EndSeparator);
                                }
                            }

                            sb.Print(sb.Format.WritingSystem.Space);

                            // Add conjunction if specified (it normally should be, if it's a series)
                            if (attribs.EndConjunction != null)
                            {
                                yield return(attribs.EndConjunction);

                                sb.Print(sb.Format.WritingSystem.Space);
                            }
                        }
                        else if (reps > 2)
                        {
                            yield return(attribs.Separator);

                            sb.Print(sb.Format.WritingSystem.Space);
                        }
                    }
                    else
                    {
                        yield return(attribs.Separator);
                    }
                }
                sb.Blocks.Push(block);                 // Now put it back

                // Prefix
                if (attribs.Before != null)
                {
                    yield return(attribs.Before);
                }

                // Content

                // Redirect output if requested
                if (attribs.Redirect != null)
                {
                    sb.AddOutputWriter();
                }

                sb.Objects.EnterScope();
                yield return(_elements[next]);

                sb.Objects.ExitScope();

                // Retrieve redirected output
                if (attribs.Redirect != null)
                {
                    sb.PushRedirectedOutput();
                    yield return(attribs.Redirect);

                    sb.PopRedirectedOutput();
                }

                // Affix
                if (attribs.After != null)
                {
                    yield return(attribs.After);
                }
            }
            sb.Blocks.Pop();

            if (attribs.End != null)
            {
                yield return(attribs.End);
            }
        }
示例#2
0
        public override IEnumerator <RantAction> Run(Sandbox sb)
        {
            var attribs = sb.NextAttribs(this);

            // Skip if chance doesn't fall within range
            if (attribs.Chance < 100 && sb.RNG.NextDouble(0, 100) > attribs.Chance)
            {
                yield break;
            }

            int    next      = -1;
            int    reps      = attribs.RepEach ? _items.Count : attribs.Repetitions;
            var    block     = new BlockState(attribs.Repetitions);
            double weightSum = _constantWeightSum;

            if (attribs.Start != null)
            {
                yield return(attribs.Start);
            }

            if (_weighted && attribs.Sync == null)
            {
                foreach (var dw in _dynamicWeights)
                {
                    sb.AddOutputWriter();
                    yield return(dw.Item2);

                    var strWeight = sb.Return().Main;
                    if (!Double.TryParse(strWeight, out _weights[dw.Item1]))
                    {
                        throw new RantRuntimeException(sb.Pattern, dw.Item2.Range,
                                                       $"Dynamic weight returned invalid weight value: '{strWeight}'");
                    }
                    weightSum += _weights[dw.Item1];
                }
            }

            sb.Blocks.Push(block);
            for (int i = 0; i < reps; i++)
            {
                if (_weighted)
                {
                    double choice = sb.RNG.NextDouble(weightSum);
                    for (int j = 0; j < _count; j++)
                    {
                        if (choice < _weights[j])
                        {
                            next = j;
                            break;
                        }
                        choice -= _weights[j];
                    }
                }
                else
                {
                    next = attribs.NextIndex(_count, sb.RNG);
                }

                if (next == -1)
                {
                    break;
                }
                block.Next(next);

                sb.Blocks.Pop();                 // Don't allow separator to access block state
                // Separator
                if (i > 0 && attribs.Separator != null)
                {
                    if (attribs.IsSeries)
                    {
                        // Check if we're on the last separator in a series
                        if (i == reps - 1)
                        {
                            // Add the oxford comma if specified
                            if (attribs.EndSeparator != null)
                            {
                                // If there are more than two items, print it!
                                if (reps > 2)
                                {
                                    yield return(attribs.EndSeparator);
                                }
                            }

                            sb.Print(sb.Format.StandardSpace);

                            // Add conjunction if specified (it normally should be, if it's a series)
                            if (attribs.EndConjunction != null)
                            {
                                yield return(attribs.EndConjunction);

                                sb.Print(sb.Format.StandardSpace);
                            }
                        }
                        else if (reps > 2)
                        {
                            yield return(attribs.Separator);

                            sb.Print(sb.Format.StandardSpace);
                        }
                    }
                    else
                    {
                        yield return(attribs.Separator);
                    }
                }
                sb.Blocks.Push(block);                 // Now put it back

                // Prefix
                if (attribs.Before != null)
                {
                    yield return(attribs.Before);
                }

                // Content
                sb.Objects.EnterScope();
                yield return(_items[next]);

                sb.Objects.ExitScope();

                // Affix
                if (attribs.After != null)
                {
                    yield return(attribs.After);
                }
            }
            sb.Blocks.Pop();

            if (attribs.End != null)
            {
                yield return(attribs.End);
            }
        }