diff --git a/Content.Tests/DMProject/Tests/Stdlib/generator_rand.dm b/Content.Tests/DMProject/Tests/Stdlib/generator_rand.dm new file mode 100644 index 0000000000..3b56e5177b --- /dev/null +++ b/Content.Tests/DMProject/Tests/Stdlib/generator_rand.dm @@ -0,0 +1,5 @@ +/proc/RunTest() + var/generator/gen = generator("num", -1, 1) + var/result = gen.Rand() + ASSERT(isnum(result)) + ASSERT((result >= -1 && result <= 1)) \ No newline at end of file diff --git a/DMCompiler/DMStandard/Types/Generator.dm b/DMCompiler/DMStandard/Types/Generator.dm index 12c2bcedb8..6b476b75f9 100644 --- a/DMCompiler/DMStandard/Types/Generator.dm +++ b/DMCompiler/DMStandard/Types/Generator.dm @@ -5,7 +5,6 @@ var/_binobj as opendream_unimplemented /generator/proc/Rand() - set opendream_unimplemented = TRUE /* Generator Theory diff --git a/OpenDreamRuntime/Objects/Types/DreamObjectVector.cs b/OpenDreamRuntime/Objects/Types/DreamObjectVector.cs index 0506b6645a..22f18e3f4f 100644 --- a/OpenDreamRuntime/Objects/Types/DreamObjectVector.cs +++ b/OpenDreamRuntime/Objects/Types/DreamObjectVector.cs @@ -338,6 +338,24 @@ public static DreamObjectVector CreateFromValue(DreamValue value, DreamObjectTre return vector; } + /// + /// Creates a from a + /// + public static DreamObjectVector CreateFromValue(Vector3 value, DreamObjectTree tree) { + var vector = tree.CreateObject(tree.Vector); + vector.Initialize(new(new(value.X), new(value.Y), new(value.Z))); + return vector; + } + + /// + /// Creates a from a + /// + public static DreamObjectVector CreateFromValue(Vector2 value, DreamObjectTree tree) { + var vector = tree.CreateObject(tree.Vector); + vector.Initialize(new(new(value.X), new(value.Y))); + return vector; + } + // TODO: Operators, supports indexing and "most math" // TODO: For loop support } diff --git a/OpenDreamRuntime/Procs/Native/DreamProcNative.cs b/OpenDreamRuntime/Procs/Native/DreamProcNative.cs index b202da6bab..e5e22c96ba 100644 --- a/OpenDreamRuntime/Procs/Native/DreamProcNative.cs +++ b/OpenDreamRuntime/Procs/Native/DreamProcNative.cs @@ -195,6 +195,8 @@ public static void SetupNativeProcs(DreamObjectTree objectTree) { objectTree.SetNativeProc(objectTree.DatabaseQuery, DreamProcNativeDatabaseQuery.NativeProc_NextRow); objectTree.SetNativeProc(objectTree.DatabaseQuery, DreamProcNativeDatabaseQuery.NativeProc_RowsAffected); + objectTree.SetNativeProc(objectTree.Generator, DreamProcNativeGenerator.NativeProc_Rand); + SetOverridableNativeProc(objectTree, objectTree.World, DreamProcNativeWorld.NativeProc_Error); SetOverridableNativeProc(objectTree, objectTree.World, DreamProcNativeWorld.NativeProc_Reboot); } diff --git a/OpenDreamRuntime/Procs/Native/DreamProcNativeGenerator.cs b/OpenDreamRuntime/Procs/Native/DreamProcNativeGenerator.cs new file mode 100644 index 0000000000..8dc321ebaa --- /dev/null +++ b/OpenDreamRuntime/Procs/Native/DreamProcNativeGenerator.cs @@ -0,0 +1,30 @@ +using OpenDreamRuntime.Objects; +using OpenDreamRuntime.Objects.Types; +using OpenDreamShared.Dream; +using Robust.Shared.Random; + +namespace OpenDreamRuntime.Procs.Native; + +internal static class DreamProcNativeGenerator { + [DreamProc("Rand")] + public static DreamValue NativeProc_Rand(NativeProc.Bundle bundle, DreamObject? src, DreamObject? usr) { + var genObj = (DreamObjectGenerator)src!; + + switch (genObj.Generator) { + case IGeneratorNum numGen: { + var result = numGen.Generate(IoCManager.Resolve()); + return new DreamValue(result); + } + case IGeneratorVector vecGen: { + var rand = IoCManager.Resolve(); + var resultObj = vecGen.PrefersVector3 + ? DreamObjectVector.CreateFromValue(vecGen.GenerateVector3(rand), bundle.ObjectTree) + : DreamObjectVector.CreateFromValue(vecGen.GenerateVector2(rand), bundle.ObjectTree); + + return new DreamValue(resultObj); + } + default: + throw new Exception($"Invalid generator for Rand: {genObj}"); + } + } +} diff --git a/OpenDreamShared/Dream/Generator.cs b/OpenDreamShared/Dream/Generator.cs index f994235916..62e2e002b7 100644 --- a/OpenDreamShared/Dream/Generator.cs +++ b/OpenDreamShared/Dream/Generator.cs @@ -31,12 +31,14 @@ public interface IGeneratorNum : IGenerator { } public interface IGeneratorVector : IGenerator { + bool PrefersVector3 { get; set; } public Vector2 GenerateVector2(IRobustRandom random); public Vector3 GenerateVector3(IRobustRandom random); } [Serializable, NetSerializable] public sealed class GeneratorNum(float low, float high, GeneratorDistribution distribution) : IGeneratorNum, IGeneratorVector { + public bool PrefersVector3 { get; set; } = false; public GeneratorNum(float value) : this(value, value, GeneratorDistribution.Constant) { } public float Generate(IRobustRandom random) { @@ -58,6 +60,7 @@ public override string ToString() { [Serializable, NetSerializable] public sealed class GeneratorVector2(Vector2 low, Vector2 high, GeneratorDistribution distribution) : IGeneratorVector { + public bool PrefersVector3 { get; set; } = false; public GeneratorVector2(Vector2 value) : this(value, value, GeneratorDistribution.Constant) { } public Vector2 GenerateVector2(IRobustRandom random) { @@ -77,6 +80,7 @@ public override string ToString() { [Serializable, NetSerializable] public sealed class GeneratorVector3(Vector3 low, Vector3 high, GeneratorDistribution distribution) : IGeneratorVector { + public bool PrefersVector3 { get; set; } = true; public GeneratorVector3(Vector3 value) : this(value, value, GeneratorDistribution.Constant) { } public Vector2 GenerateVector2(IRobustRandom random) { @@ -96,6 +100,8 @@ public override string ToString() { [Serializable, NetSerializable] public sealed class GeneratorBox2(Vector2 low, Vector2 high, GeneratorDistribution distribution) : IGeneratorVector { + public bool PrefersVector3 { get; set; } = false; + public Vector2 GenerateVector2(IRobustRandom random) { var x = IGenerator.GenerateNum(random, low.X, high.X, distribution); var y = IGenerator.GenerateNum(random, low.Y, high.Y, distribution); @@ -116,6 +122,8 @@ public override string ToString() { [Serializable, NetSerializable] public sealed class GeneratorBox3(Vector3 low, Vector3 high, GeneratorDistribution distribution) : IGeneratorVector { + public bool PrefersVector3 { get; set; } = true; + public Vector2 GenerateVector2(IRobustRandom random) { var vector = GenerateVector3(random); @@ -137,6 +145,8 @@ public override string ToString() { [Serializable, NetSerializable] public sealed class GeneratorCircle(float low, float high, GeneratorDistribution distribution) : IGeneratorVector { + public bool PrefersVector3 { get; set; } = false; + public Vector2 GenerateVector2(IRobustRandom random) { var theta = random.NextFloat(0f, 360f); var r = IGenerator.GenerateNum(random, low, high, distribution); @@ -157,6 +167,8 @@ public override string ToString() { [Serializable, NetSerializable] public sealed class GeneratorSphere(float low, float high, GeneratorDistribution distribution) : IGeneratorVector { + public bool PrefersVector3 { get; set; } = true; + public Vector2 GenerateVector2(IRobustRandom random) { var vector = GenerateVector3(random); @@ -182,6 +194,8 @@ public override string ToString() { [Serializable, NetSerializable] public sealed class GeneratorSquare(Vector2 low, Vector2 high, GeneratorDistribution distribution) : IGeneratorVector { + public bool PrefersVector3 { get; set; } = false; + public Vector2 GenerateVector2(IRobustRandom random) { var x = IGenerator.GenerateNum(random, -high.X, high.X, distribution); var y = IGenerator.GenerateNum(random, -high.Y, high.Y, distribution); @@ -207,6 +221,8 @@ public override string ToString() { [Serializable, NetSerializable] public sealed class GeneratorCube(Vector3 low, Vector3 high, GeneratorDistribution distribution) : IGeneratorVector { + public bool PrefersVector3 { get; set; } = true; + public Vector2 GenerateVector2(IRobustRandom random) { var vector = GenerateVector3(random);