diff --git a/DMCompiler/Bytecode/DreamProcOpcode.cs b/DMCompiler/Bytecode/DreamProcOpcode.cs
index 53ec087bba..17c8a7a973 100644
--- a/DMCompiler/Bytecode/DreamProcOpcode.cs
+++ b/DMCompiler/Bytecode/DreamProcOpcode.cs
@@ -131,10 +131,10 @@ public enum DreamProcOpcode : byte {
Sin = 0x79,
Cos = 0x7A,
Tan = 0x7B,
- Arcsin = 0x7C,
- Arccos = 0x7D,
- Arctan = 0x7E,
- Arctan2 = 0x7F,
+ ArcSin = 0x7C,
+ ArcCos = 0x7D,
+ ArcTan = 0x7E,
+ ArcTan2 = 0x7F,
Sqrt = 0x80,
Log = 0x81,
LogE = 0x82,
diff --git a/DMCompiler/DM/DMProc.cs b/DMCompiler/DM/DMProc.cs
index 5c4a58f996..8ba88da617 100644
--- a/DMCompiler/DM/DMProc.cs
+++ b/DMCompiler/DM/DMProc.cs
@@ -957,21 +957,21 @@ public void Tan() {
WriteOpcode(DreamProcOpcode.Tan);
}
- public void Arcsin() {
- WriteOpcode(DreamProcOpcode.Arcsin);
+ public void ArcSin() {
+ WriteOpcode(DreamProcOpcode.ArcSin);
}
- public void Arccos() {
- WriteOpcode(DreamProcOpcode.Arccos);
+ public void ArcCos() {
+ WriteOpcode(DreamProcOpcode.ArcCos);
}
- public void Arctan() {
- WriteOpcode(DreamProcOpcode.Arctan);
+ public void ArcTan() {
+ WriteOpcode(DreamProcOpcode.ArcTan);
}
- public void Arctan2() {
+ public void ArcTan2() {
ShrinkStack(1);
- WriteOpcode(DreamProcOpcode.Arctan2);
+ WriteOpcode(DreamProcOpcode.ArcTan2);
}
public void Sqrt() {
diff --git a/DMCompiler/DM/Expressions/Builtins.cs b/DMCompiler/DM/Expressions/Builtins.cs
index 280dd67e09..ab46a0fc31 100644
--- a/DMCompiler/DM/Expressions/Builtins.cs
+++ b/DMCompiler/DM/Expressions/Builtins.cs
@@ -3,6 +3,7 @@
using OpenDreamShared.Dream;
using OpenDreamShared.Json;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using DMCompiler.Bytecode;
namespace DMCompiler.DM.Expressions {
@@ -644,20 +645,26 @@ public override void EmitPushValue(DMObject dmObject, DMProc proc) {
}
}
- class Sin : DMExpression {
- DMExpression _expr;
+ internal class Sin : DMExpression {
+ private readonly DMExpression _expr;
public Sin(Location location, DMExpression expr) : base(location) {
_expr = expr;
}
-
- public override bool TryAsConstant(out Constant constant) {
+
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
- constant = constant.Sin();
+ if (constant is not Number {Value: var x}) {
+ x = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _expr.Location,
+ "Invalid value treated as 0, sin(0) will always be 0");
+ }
+
+ constant = new Number(Location, SharedOperations.Sin(x));
return true;
}
@@ -667,20 +674,26 @@ public override void EmitPushValue(DMObject dmObject, DMProc proc) {
}
}
- class Cos : DMExpression {
- DMExpression _expr;
+ internal class Cos : DMExpression {
+ private readonly DMExpression _expr;
public Cos(Location location, DMExpression expr) : base(location) {
_expr = expr;
}
-
- public override bool TryAsConstant(out Constant constant) {
+
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
- constant = constant.Cos();
+ if (constant is not Number {Value: var x}) {
+ x = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _expr.Location,
+ "Invalid value treated as 0, cos(0) will always be 1");
+ }
+
+ constant = new Number(Location, SharedOperations.Cos(x));
return true;
}
@@ -690,20 +703,26 @@ public override void EmitPushValue(DMObject dmObject, DMProc proc) {
}
}
- class Tan : DMExpression {
- DMExpression _expr;
+ internal class Tan : DMExpression {
+ private readonly DMExpression _expr;
public Tan(Location location, DMExpression expr) : base(location) {
_expr = expr;
}
-
- public override bool TryAsConstant(out Constant constant) {
+
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
- constant = constant.Tan();
+ if (constant is not Number {Value: var x}) {
+ x = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _expr.Location,
+ "Invalid value treated as 0, tan(0) will always be 0");
+ }
+
+ constant = new Number(Location, SharedOperations.Tan(x));
return true;
}
@@ -713,115 +732,164 @@ public override void EmitPushValue(DMObject dmObject, DMProc proc) {
}
}
- class Arcsin : DMExpression {
- DMExpression _expr;
+ internal class ArcSin : DMExpression {
+ private readonly DMExpression _expr;
- public Arcsin(Location location, DMExpression expr) : base(location) {
+ public ArcSin(Location location, DMExpression expr) : base(location) {
_expr = expr;
}
-
- public override bool TryAsConstant(out Constant constant) {
+
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
- constant = constant.Arcsin();
+ if (constant is not Number {Value: var x}) {
+ x = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _expr.Location,
+ "Invalid value treated as 0, arcsin(0) will always be 0");
+ }
+
+ if (x is < -1 or > 1) {
+ DMCompiler.Emit(WarningCode.BadArgument, _expr.Location, $"Invalid value {x}, must be >= -1 and <= 1");
+ x = 0;
+ }
+
+ constant = new Number(Location, SharedOperations.ArcSin(x));
return true;
}
public override void EmitPushValue(DMObject dmObject, DMProc proc) {
_expr.EmitPushValue(dmObject, proc);
- proc.Arcsin();
+ proc.ArcSin();
}
}
- class Arccos : DMExpression {
- DMExpression _expr;
+ internal class ArcCos : DMExpression {
+ private readonly DMExpression _expr;
- public Arccos(Location location, DMExpression expr) : base(location) {
+ public ArcCos(Location location, DMExpression expr) : base(location) {
_expr = expr;
}
-
- public override bool TryAsConstant(out Constant constant) {
+
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
- constant = constant.Arccos();
+ if (constant is not Number {Value: var x}) {
+ x = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _expr.Location,
+ "Invalid value treated as 0, arccos(0) will always be 1");
+ }
+
+ if (x is < -1 or > 1) {
+ DMCompiler.Emit(WarningCode.BadArgument, _expr.Location, $"Invalid value {x}, must be >= -1 and <= 1");
+ x = 0;
+ }
+
+ constant = new Number(Location, SharedOperations.ArcCos(x));
return true;
}
public override void EmitPushValue(DMObject dmObject, DMProc proc) {
_expr.EmitPushValue(dmObject, proc);
- proc.Arccos();
+ proc.ArcCos();
}
}
- class Arctan : DMExpression {
- DMExpression _expr;
+ internal class ArcTan : DMExpression {
+ private readonly DMExpression _expr;
- public Arctan(Location location, DMExpression expr) : base(location) {
+ public ArcTan(Location location, DMExpression expr) : base(location) {
_expr = expr;
}
-
- public override bool TryAsConstant(out Constant constant) {
+
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
- constant = constant.Arctan();
+ if (constant is not Number {Value: var a}) {
+ a = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _expr.Location,
+ "Invalid value treated as 0, arctan(0) will always be 0");
+ }
+
+ constant = new Number(Location, SharedOperations.ArcTan(a));
return true;
}
public override void EmitPushValue(DMObject dmObject, DMProc proc) {
_expr.EmitPushValue(dmObject, proc);
- proc.Arctan();
+ proc.ArcTan();
}
}
- class Arctan2 : DMExpression {
- DMExpression _xexpr;
- DMExpression _yexpr;
+ internal class ArcTan2 : DMExpression {
+ private readonly DMExpression _xExpr;
+ private readonly DMExpression _yExpr;
- public Arctan2(Location location, DMExpression xexpr, DMExpression yexpr) : base(location) {
- _xexpr = xexpr;
- _yexpr = yexpr;
+ public ArcTan2(Location location, DMExpression xExpr, DMExpression yExpr) : base(location) {
+ _xExpr = xExpr;
+ _yExpr = yExpr;
}
-
- public override bool TryAsConstant(out Constant constant) {
- if (!_xexpr.TryAsConstant(out Constant xconst) || !_yexpr.TryAsConstant(out Constant yconst)) {
+
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
+ if (!_xExpr.TryAsConstant(out var xConst) || !_yExpr.TryAsConstant(out var yConst)) {
constant = null;
return false;
}
- constant = xconst.Arctan2(yconst);
+ if (xConst is not Number {Value: var x}) {
+ x = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _xExpr.Location, "Invalid x value treated as 0");
+ }
+
+ if (yConst is not Number {Value: var y}) {
+ y = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _xExpr.Location, "Invalid y value treated as 0");
+ }
+
+ constant = new Number(Location, SharedOperations.ArcTan(x, y));
return true;
}
public override void EmitPushValue(DMObject dmObject, DMProc proc) {
- _xexpr.EmitPushValue(dmObject, proc);
- _yexpr.EmitPushValue(dmObject, proc);
- proc.Arctan2();
+ _xExpr.EmitPushValue(dmObject, proc);
+ _yExpr.EmitPushValue(dmObject, proc);
+ proc.ArcTan2();
}
}
- class Sqrt : DMExpression {
- DMExpression _expr;
+ internal class Sqrt : DMExpression {
+ private readonly DMExpression _expr;
public Sqrt(Location location, DMExpression expr) : base(location) {
_expr = expr;
}
- public override bool TryAsConstant(out Constant constant) {
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
- constant = constant.Sqrt();
+ if (constant is not Number {Value: var a}) {
+ a = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _expr.Location,
+ "Invalid value treated as 0, sqrt(0) will always be 0");
+ }
+
+ if (a < 0) {
+ DMCompiler.Emit(WarningCode.BadArgument, _expr.Location,
+ $"Cannot get the square root of a negative number ({a})");
+ }
+
+ constant = new Number(Location, SharedOperations.Sqrt(a));
return true;
}
@@ -831,32 +899,44 @@ public override void EmitPushValue(DMObject dmObject, DMProc proc) {
}
}
- class Log : DMExpression {
- DMExpression _expr;
- DMExpression? _baseExpr;
+ internal class Log : DMExpression {
+ private readonly DMExpression _expr;
+ private readonly DMExpression? _baseExpr;
public Log(Location location, DMExpression expr, DMExpression? baseExpr) : base(location) {
_expr = expr;
_baseExpr = baseExpr;
}
-
- public override bool TryAsConstant(out Constant constant) {
+
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
+ if (constant is not Number {Value: var value} || value <= 0) {
+ value = 1;
+ DMCompiler.Emit(WarningCode.BadArgument, _expr.Location,
+ "Invalid value, must be a number greater than 0");
+ }
+
if (_baseExpr == null) {
- constant = constant.Log(null);
+ constant = new Number(Location, SharedOperations.Log(value));
return true;
}
- if (!_baseExpr.TryAsConstant(out Constant baseConstant)) {
+ if (!_baseExpr.TryAsConstant(out var baseConstant)) {
constant = null;
return false;
}
- constant = constant.Log(baseConstant);
+ if (baseConstant is not Number {Value: var baseValue} || baseValue <= 0) {
+ baseValue = 10;
+ DMCompiler.Emit(WarningCode.BadArgument, _baseExpr.Location,
+ "Invalid base, must be a number greater than 0");
+ }
+
+ constant = new Number(Location, SharedOperations.Log(value, baseValue));
return true;
}
@@ -871,20 +951,26 @@ public override void EmitPushValue(DMObject dmObject, DMProc proc) {
}
}
- class Abs : DMExpression {
- DMExpression _expr;
+ internal class Abs : DMExpression {
+ private readonly DMExpression _expr;
public Abs(Location location, DMExpression expr) : base(location) {
_expr = expr;
}
- public override bool TryAsConstant(out Constant constant) {
+ public override bool TryAsConstant([NotNullWhen(true)] out Constant? constant) {
if (!_expr.TryAsConstant(out constant)) {
constant = null;
return false;
}
- constant = constant.Abs();
+ if (constant is not Number {Value: var a}) {
+ a = 0;
+ DMCompiler.Emit(WarningCode.FallbackBuiltinArgument, _expr.Location,
+ "Invalid value treated as 0, abs(0) will always be 0");
+ }
+
+ constant = new Number(Location, SharedOperations.Abs(a));
return true;
}
diff --git a/DMCompiler/DM/Expressions/Constant.cs b/DMCompiler/DM/Expressions/Constant.cs
index f7d00a87ae..c8391830aa 100644
--- a/DMCompiler/DM/Expressions/Constant.cs
+++ b/DMCompiler/DM/Expressions/Constant.cs
@@ -97,49 +97,6 @@ public virtual Constant LessThan(Constant rhs) {
public virtual Constant LessThanOrEqual(Constant rhs) {
throw new CompileErrorException(Location, $"const operation \"{this} <= {rhs}\" is invalid");
}
-
- public virtual Constant Sin() {
- throw new CompileErrorException(Location, $"const operation \"sin({this})\" is invalid");
- }
-
- public virtual Constant Cos() {
- throw new CompileErrorException(Location, $"const operation \"cos({this})\" is invalid");
- }
-
- public virtual Constant Tan() {
- throw new CompileErrorException(Location, $"const operation \"tan({this})\" is invalid");
- }
-
- public virtual Constant Arcsin() {
- throw new CompileErrorException(Location, $"const operation \"arcsin({this})\" is invalid");
- }
-
- public virtual Constant Arccos() {
- throw new CompileErrorException(Location, $"const operation \"arccos({this})\" is invalid");
- }
-
- public virtual Constant Arctan() {
- throw new CompileErrorException(Location, $"const operation \"arctan({this})\" is invalid");
- }
-
- public virtual Constant Arctan2(Constant yConst) {
- throw new CompileErrorException(Location, $"const operation \"arctan({this}, {yConst})\" is invalid");
- }
-
- public virtual Constant Sqrt() {
- throw new CompileErrorException(Location, $"const operation \"sqrt({this})\" is invalid");
- }
-
- public virtual Constant Log(Constant? baseVal) {
- if (baseVal == null) {
- throw new CompileErrorException(Location, $"const operation \"log({this})\" is invalid");
- }
- throw new CompileErrorException(Location, $"const operation \"log({baseVal}, {this})\" is invalid");
- }
-
- public virtual Constant Abs() {
- throw new CompileErrorException(Location, $"const operation \"abs({this})\" is invalid");
- }
#endregion
}
@@ -359,70 +316,6 @@ public override Constant LessThanOrEqual(Constant rhs) {
}
return new Number(Location, (Value <= rhsNum.Value) ? 1 : 0);
}
-
- public override Constant Sin() {
- return new Number(Location, MathF.Sin(Value / 180 * MathF.PI));
- }
-
- public override Constant Cos() {
- return new Number(Location, MathF.Cos(Value / 180 * MathF.PI));
- }
-
- public override Constant Tan() {
- return new Number(Location, MathF.Tan(Value / 180 * MathF.PI));
- }
-
- public override Constant Arcsin() {
- if (Value < -1 || Value > 1) {
- throw new CompileErrorException(Location, $"const operation \"arcsin({this})\" is invalid (out of range)");
- }
- return new Number(Location, MathF.Asin(Value) / MathF.PI * 180);
- }
-
- public override Constant Arccos() {
- if (Value < -1 || Value > 1) {
- throw new CompileErrorException(Location, $"const operation \"arccos({this})\" is invalid (out of range)");
- }
- return new Number(Location, MathF.Acos(Value) / MathF.PI * 180);
- }
-
- public override Constant Arctan() {
- return new Number(Location, MathF.Atan(Value) / MathF.PI * 180);
- }
-
- public override Constant Arctan2(Constant yConst) {
- if (yConst is not Number yNum) {
- throw new CompileErrorException(Location, $"const operation \"arctan2({this}, {yConst})\" is invalid");
- }
- return new Number(Location, MathF.Atan2(yNum.Value, Value) / MathF.PI * 180);
- }
-
- public override Constant Sqrt() {
- if (Value < 0) {
- throw new CompileErrorException(Location, $"const operation \"sqrt({this})\" is invalid (negative)");
- }
- return new Number(Location, MathF.Sqrt(Value));
- }
-
- public override Constant Log(Constant? baseVal) {
- if (Value <= 0) {
- throw new CompileErrorException(Location, $"const operation \"log({this})\" is invalid (non-positive)");
- }
- if (baseVal == null) {
- return new Number(Location, MathF.Log(Value));
- }
- if (baseVal is not Number baseNum) {
- throw new CompileErrorException(Location, $"const operation \"log({this}, {baseVal})\" is invalid");
- }
- if (baseNum.Value <= 0) {
- throw new CompileErrorException(Location, $"const operation \"log({this}, {baseVal})\" is invalid (non-positive base)");
- }
- return new Number(Location, MathF.Log(Value, baseNum.Value));
- }
-
- public override Constant Abs() {
- return new Number(Location, MathF.Abs(Value));
- }
}
// "abc"
diff --git a/DMCompiler/DM/Visitors/DMVisitorExpression.cs b/DMCompiler/DM/Visitors/DMVisitorExpression.cs
index 9d711dc4c3..8acb35a0dc 100644
--- a/DMCompiler/DM/Visitors/DMVisitorExpression.cs
+++ b/DMCompiler/DM/Visitors/DMVisitorExpression.cs
@@ -996,23 +996,23 @@ public void VisitTan(DMASTTan tan) {
public void VisitArcsin(DMASTArcsin arcsin) {
var expr = DMExpression.Create(_dmObject, _proc, arcsin.Expression, _inferredPath);
- Result = new Expressions.Arcsin(arcsin.Location, expr);
+ Result = new Expressions.ArcSin(arcsin.Location, expr);
}
public void VisitArccos(DMASTArccos arccos) {
var expr = DMExpression.Create(_dmObject, _proc, arccos.Expression, _inferredPath);
- Result = new Expressions.Arccos(arccos.Location, expr);
+ Result = new Expressions.ArcCos(arccos.Location, expr);
}
public void VisitArctan(DMASTArctan arctan) {
var expr = DMExpression.Create(_dmObject, _proc, arctan.Expression, _inferredPath);
- Result = new Expressions.Arctan(arctan.Location, expr);
+ Result = new Expressions.ArcTan(arctan.Location, expr);
}
public void VisitArctan2(DMASTArctan2 arctan2) {
var xexpr = DMExpression.Create(_dmObject, _proc, arctan2.XExpression, _inferredPath);
var yexpr = DMExpression.Create(_dmObject, _proc, arctan2.YExpression, _inferredPath);
- Result = new Expressions.Arctan2(arctan2.Location, xexpr, yexpr);
+ Result = new Expressions.ArcTan2(arctan2.Location, xexpr, yexpr);
}
public void VisitSqrt(DMASTSqrt sqrt) {
diff --git a/DMCompiler/DMStandard/DefaultPragmaConfig.dm b/DMCompiler/DMStandard/DefaultPragmaConfig.dm
index 7526cc2396..2c71d6c4e4 100644
--- a/DMCompiler/DMStandard/DefaultPragmaConfig.dm
+++ b/DMCompiler/DMStandard/DefaultPragmaConfig.dm
@@ -19,6 +19,7 @@
#pragma PointlessParentCall warning
#pragma PointlessBuiltinCall warning
#pragma SuspiciousMatrixCall warning
+#pragma FallbackBuiltinArgument warning
#pragma MalformedRange warning
#pragma InvalidRange error
#pragma InvalidSetStatement error
diff --git a/DMCompiler/SharedOperations.cs b/DMCompiler/SharedOperations.cs
new file mode 100644
index 0000000000..a29482757c
--- /dev/null
+++ b/DMCompiler/SharedOperations.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace DMCompiler;
+
+///
+/// A class containing operations used by both the compiler and the server.
+/// Helps make sure things like sin() and cos() give the same result on both.
+///
+public static class SharedOperations {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Sin(float x) {
+ return MathF.Sin(x / 180 * MathF.PI);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Cos(float x) {
+ return MathF.Cos(x / 180 * MathF.PI);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Tan(float x) {
+ return MathF.Tan(x / 180 * MathF.PI);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float ArcSin(float x) {
+ return MathF.Asin(x) / MathF.PI * 180;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float ArcCos(float x) {
+ return MathF.Acos(x) / MathF.PI * 180;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float ArcTan(float a) {
+ return MathF.Atan(a) / MathF.PI * 180;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float ArcTan(float x, float y) {
+ return MathF.Atan2(y, x) / MathF.PI * 180;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Sqrt(float a) {
+ return MathF.Sqrt(a);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Log(float y) {
+ return MathF.Log(y);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Log(float y, float baseValue) {
+ return MathF.Log(y, baseValue);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Abs(float a) {
+ return MathF.Abs(a);
+ }
+}
diff --git a/OpenDream.sln.DotSettings b/OpenDream.sln.DotSettings
index 06cd921c58..b9158a88ff 100644
--- a/OpenDream.sln.DotSettings
+++ b/OpenDream.sln.DotSettings
@@ -9,6 +9,9 @@
RHS
UI
True
+ True
+ True
+ True
True
True
True
diff --git a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
index 4bd131d69a..da20d51b32 100644
--- a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
+++ b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
@@ -4,6 +4,7 @@
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
+using DMCompiler;
using DMCompiler.Bytecode;
using OpenDreamRuntime.Objects;
using OpenDreamRuntime.Objects.Types;
@@ -1619,82 +1620,92 @@ public static ProcStatus EndTry(DMProcState state) {
}
public static ProcStatus Sin(DMProcState state) {
- DreamValue value = state.Pop();
+ float x = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.Sin(x);
- state.Push(new DreamValue(MathF.Sin(value.UnsafeGetValueAsFloat() / 180 * MathF.PI)));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
public static ProcStatus Cos(DMProcState state) {
- DreamValue value = state.Pop();
+ float x = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.Cos(x);
- state.Push(new DreamValue(MathF.Cos(value.UnsafeGetValueAsFloat() / 180 * MathF.PI)));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
public static ProcStatus Tan(DMProcState state) {
- DreamValue value = state.Pop();
+ float x = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.Tan(x);
- state.Push(new DreamValue(MathF.Tan(value.UnsafeGetValueAsFloat() / 180 * MathF.PI)));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
- public static ProcStatus Arcsin(DMProcState state) {
- DreamValue value = state.Pop();
+ public static ProcStatus ArcSin(DMProcState state) {
+ float x = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.ArcSin(x);
- state.Push(new DreamValue(MathF.Asin(value.UnsafeGetValueAsFloat()) / MathF.PI * 180));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
- public static ProcStatus Arccos(DMProcState state) {
- DreamValue value = state.Pop();
+ public static ProcStatus ArcCos(DMProcState state) {
+ float x = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.ArcCos(x);
- state.Push(new DreamValue(MathF.Acos(value.UnsafeGetValueAsFloat()) / MathF.PI * 180));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
- public static ProcStatus Arctan(DMProcState state) {
- DreamValue value = state.Pop();
+ public static ProcStatus ArcTan(DMProcState state) {
+ float a = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.ArcTan(a);
- state.Push(new DreamValue(MathF.Atan(value.UnsafeGetValueAsFloat()) / MathF.PI * 180));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
- public static ProcStatus Arctan2(DMProcState state) {
- DreamValue y = state.Pop();
- DreamValue x = state.Pop();
- var yValue = y.UnsafeGetValueAsFloat();
+ public static ProcStatus ArcTan2(DMProcState state) {
+ float y = state.Pop().UnsafeGetValueAsFloat();
+ float x = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.ArcTan(x, y);
- state.Push(new DreamValue(MathF.Atan2(yValue, x.UnsafeGetValueAsFloat()) / MathF.PI * 180));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
public static ProcStatus Sqrt(DMProcState state) {
- DreamValue value = state.Pop();
+ float a = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.Sqrt(a);
- state.Push(new DreamValue(MathF.Sqrt(value.UnsafeGetValueAsFloat())));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
public static ProcStatus Log(DMProcState state) {
- DreamValue baseValue = state.Pop();
- DreamValue value = state.Pop();
+ float baseValue = state.Pop().UnsafeGetValueAsFloat();
+ float value = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.Log(value, baseValue);
- state.Push(new DreamValue(MathF.Log(value.UnsafeGetValueAsFloat(), baseValue.UnsafeGetValueAsFloat())));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
public static ProcStatus LogE(DMProcState state) {
- DreamValue value = state.Pop();
+ float y = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.Log(y);
- state.Push(new DreamValue(MathF.Log(value.UnsafeGetValueAsFloat())));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
public static ProcStatus Abs(DMProcState state) {
- DreamValue value = state.Pop();
+ float a = state.Pop().UnsafeGetValueAsFloat();
+ float result = SharedOperations.Abs(a);
- state.Push(new DreamValue(MathF.Abs(value.UnsafeGetValueAsFloat())));
+ state.Push(new DreamValue(result));
return ProcStatus.Continue;
}
diff --git a/OpenDreamRuntime/Procs/DMProc.cs b/OpenDreamRuntime/Procs/DMProc.cs
index 37be0c73c8..ca8d51a094 100644
--- a/OpenDreamRuntime/Procs/DMProc.cs
+++ b/OpenDreamRuntime/Procs/DMProc.cs
@@ -288,10 +288,10 @@ public sealed class DMProcState : ProcState {
{DreamProcOpcode.Sin, DMOpcodeHandlers.Sin},
{DreamProcOpcode.Cos, DMOpcodeHandlers.Cos},
{DreamProcOpcode.Tan, DMOpcodeHandlers.Tan},
- {DreamProcOpcode.Arcsin, DMOpcodeHandlers.Arcsin},
- {DreamProcOpcode.Arccos, DMOpcodeHandlers.Arccos},
- {DreamProcOpcode.Arctan, DMOpcodeHandlers.Arctan},
- {DreamProcOpcode.Arctan2, DMOpcodeHandlers.Arctan2},
+ {DreamProcOpcode.ArcSin, DMOpcodeHandlers.ArcSin},
+ {DreamProcOpcode.ArcCos, DMOpcodeHandlers.ArcCos},
+ {DreamProcOpcode.ArcTan, DMOpcodeHandlers.ArcTan},
+ {DreamProcOpcode.ArcTan2, DMOpcodeHandlers.ArcTan2},
{DreamProcOpcode.Sqrt, DMOpcodeHandlers.Sqrt},
{DreamProcOpcode.Log, DMOpcodeHandlers.Log},
{DreamProcOpcode.LogE, DMOpcodeHandlers.LogE},
diff --git a/OpenDreamShared/Compiler/CompilerError.cs b/OpenDreamShared/Compiler/CompilerError.cs
index a6bb60e0e8..0c468ffd54 100644
--- a/OpenDreamShared/Compiler/CompilerError.cs
+++ b/OpenDreamShared/Compiler/CompilerError.cs
@@ -44,6 +44,7 @@ public enum WarningCode {
PointlessParentCall = 2205,
PointlessBuiltinCall = 2206, // For pointless calls to issaved() or initial()
SuspiciousMatrixCall = 2207, // Calling matrix() with seemingly the wrong arguments
+ FallbackBuiltinArgument = 2208, // A builtin (sin(), cos(), etc) with an invalid/fallback argument
MalformedRange = 2300,
InvalidRange = 2301,
InvalidSetStatement = 2302,