Пример #1
0
        public override IEnumerator<RantAction> Run(Sandbox sb)
		{
			var attribs = sb.NextAttribs(this);
			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) 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;
		}
Пример #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;
		}