Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement 516 values_ procs #2213

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Content.Tests/DMProject/Tests/Builtins/values_cut.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

/proc/RunTest()
var/list/one = list("a"=1, "b"=2, "c"=-3)
ASSERT(values_cut_under(one, 5, 1) == 3)

var/list/two = list("a"=1, "b"=2, "c"=0)
ASSERT(values_cut_under(two, 1) == 1)

var/list/three = list("a"=1, "b"=2, "c"=0)
ASSERT(values_cut_under(three, 1, TRUE) == 2)

var/list/four = list("a"=1, "b"=2, "c"=-3)
ASSERT(values_cut_over(four, 5, 1) == 0)

var/list/five = list("a"=1, "b"=2, "c"=0)
ASSERT(values_cut_over(five, 1) == 1)

var/list/six = list("a"=1, "b"=2, "c"=0)
ASSERT(values_cut_over(six, 1, TRUE) == 2)

var/list/seven = list("a", "b", "c")
ASSERT(values_cut_under(seven, -1, 0) == 3)

var/list/eight = list("a"=1, "b", "c"=-3)
ASSERT(values_cut_under(eight, -1, 0) == 2)
5 changes: 5 additions & 0 deletions Content.Tests/DMProject/Tests/Builtins/values_dot.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

/proc/RunTest()
ASSERT(values_dot(list(a=2.4,b=1,c=7),list(a=2,b=4,c=null)) == 8.8)
ASSERT(values_dot(list(),list(a=2,b=4)) == 0)
ASSERT(values_dot(list("a"),list(a=2,b=4)) == 0)
9 changes: 9 additions & 0 deletions Content.Tests/DMProject/Tests/Builtins/values_product.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

/proc/RunTest()
ASSERT(values_product(null) == 1)
ASSERT(values_product(list(5)) == 1)
ASSERT(values_product(list(a=2)) == 2)
ASSERT(values_product(list(a=2,b=0)) == 0)
ASSERT(values_product(list(a=2,b=null)) == 2)
ASSERT(values_product(list(a=2,b=list(c=5))) == 2)
ASSERT(values_product(list(a=2,b=4.4)) == 8.8)
9 changes: 9 additions & 0 deletions Content.Tests/DMProject/Tests/Builtins/values_sum.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

/proc/RunTest()
ASSERT(values_sum(null) == 0)
ASSERT(values_sum(list(5)) == 0)
ASSERT(values_sum(list(a=2)) == 2)
ASSERT(values_sum(list(a=2,b=0)) == 2)
ASSERT(values_sum(list(a=2,b=null)) == 2)
ASSERT(values_sum(list(a=2,b=list(c=5))) == 2)
ASSERT(values_sum(list(a=2,b=4.4)) == 6.4)
5 changes: 5 additions & 0 deletions DMCompiler/DMStandard/_Standard.dm
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ proc/typesof(Item1) as /list
proc/uppertext(T as text) as text
proc/url_decode(UrlText) as text
proc/url_encode(PlainText, format = 0) as text
proc/values_cut_over(Alist, Max, inclusive = 0) as num
proc/values_cut_under(Alist, Min, inclusive = 0) as num
proc/values_dot(A, B) as num
proc/values_product(Alist) as num
proc/values_sum(Alist) as num
proc/view(Dist = 5, Center = usr) as /list
proc/viewers(Depth, Center = usr) as /list
proc/walk(Ref, Dir, Lag = 0, Speed = 0)
Expand Down
5 changes: 5 additions & 0 deletions OpenDreamRuntime/Procs/Native/DreamProcNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ public static void SetupNativeProcs(DreamObjectTree objectTree) {
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_uppertext);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_url_decode);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_url_encode);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_values_cut_over);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_values_cut_under);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_values_dot);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_values_product);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_values_sum);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_view);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_viewers);
objectTree.SetGlobalNativeProc(DreamProcNativeRoot.NativeProc_walk);
Expand Down
146 changes: 146 additions & 0 deletions OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3108,6 +3108,152 @@ public static DreamValue NativeProc_url_encode(NativeProc.Bundle bundle, DreamOb
return new DreamValue(HttpUtility.UrlEncode(plainText));
}

[DreamProc("values_cut_over")]
[DreamProcParameter("Alist", Type = DreamValueTypeFlag.DreamObject)]
[DreamProcParameter("Max", Type = DreamValueTypeFlag.Float)]
[DreamProcParameter("inclusive", Type = DreamValueTypeFlag.Float, DefaultValue = 0)]
public static DreamValue NativeProc_values_cut_over(NativeProc.Bundle bundle, DreamObject? src, DreamObject? usr) {
if (bundle.Arguments.Length < 2 || bundle.Arguments.Length > 3) throw new Exception($"expected 2-3 arguments (found {bundle.Arguments.Length})");

DreamValue argList = bundle.GetArgument(0, "Alist");
DreamValue argMin = bundle.GetArgument(1, "Max");
DreamValue argInclusive = bundle.GetArgument(2, "inclusive");

return values_cut_helper(argList, argMin, argInclusive, false);
}

[DreamProc("values_cut_under")]
[DreamProcParameter("Alist", Type = DreamValueTypeFlag.DreamObject)]
[DreamProcParameter("Min", Type = DreamValueTypeFlag.Float)]
[DreamProcParameter("inclusive", Type = DreamValueTypeFlag.Float, DefaultValue = 0)]
public static DreamValue NativeProc_values_cut_under(NativeProc.Bundle bundle, DreamObject? src, DreamObject? usr) {
if (bundle.Arguments.Length < 2 || bundle.Arguments.Length > 3) throw new Exception($"expected 2-3 arguments (found {bundle.Arguments.Length})");

DreamValue argList = bundle.GetArgument(0, "Alist");
DreamValue argMin = bundle.GetArgument(1, "Min");
DreamValue argInclusive = bundle.GetArgument(2, "inclusive");

return values_cut_helper(argList, argMin, argInclusive, true);
}

private static DreamValue values_cut_helper(DreamValue argList, DreamValue argMin, DreamValue argInclusive, bool under) {
// BYOND explicitly doesn't check for any truthy value
bool inclusive = argInclusive.TryGetValueAsFloat(out var inclusiveValue) && inclusiveValue >= 1;

var cutCount = 0; // number of values cut from the list
var min = argMin.UnsafeGetValueAsFloat();

if (argList.TryGetValueAsDreamList(out var list)) {
if (!list.IsAssociative) {
cutCount = list.GetLength();
list.Cut();
return new DreamValue(cutCount);
}

var values = list.GetValues();
var assocValues = list.GetAssociativeValues();

// Nuke any keys without values
if (values.Count != assocValues.Count) {
// We need to copy the list so we can modify while enumerating
var listCopy = new List<DreamValue>(values);
foreach (var val in listCopy) {
Comment on lines +3158 to +3160
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be possible to make this a for(...; ...; ...) loop instead. That could end up depending on list.RemoveValue()'s behavior though.

if (!assocValues.ContainsKey(val)) {
cutCount += 1;
list.RemoveValue(val);
}
}
}

foreach (var (key,value) in assocValues) {
if (value.TryGetValueAsFloat(out var valFloat)) {
switch (inclusive)
{
case true when under && valFloat <= min:
case true when !under && valFloat >= min:
case false when under && valFloat < min:
case false when !under && valFloat > min:
list.RemoveValue(key);
cutCount += 1;
break;
}
} else {
list.RemoveValue(key); // Keys without numeric values seem to always be removed
cutCount += 1;
}
}
}

return new DreamValue(cutCount);
}

[DreamProc("values_dot")]
[DreamProcParameter("A", Type = DreamValueTypeFlag.DreamObject)]
[DreamProcParameter("B", Type = DreamValueTypeFlag.DreamObject)]
public static DreamValue NativeProc_values_dot(NativeProc.Bundle bundle, DreamObject? src, DreamObject? usr) {
if (bundle.Arguments.Length != 2) throw new Exception("expected 2 arguments");

DreamValue argA = bundle.GetArgument(0, "A");
DreamValue argB = bundle.GetArgument(1, "B");

float sum = 0; // Default return is 0 for invalid args

if (argA.TryGetValueAsDreamList(out var listA) && listA.IsAssociative && argB.TryGetValueAsDreamList(out var listB) && listB.IsAssociative) {
var aValues = listA.GetAssociativeValues();
var bValues = listB.GetAssociativeValues();

// sum += valueA * valueB
// for each assoc value whose key exists in both lists
// and when both assoc values are floats
foreach (var (key,value) in aValues) {
if (value.TryGetValueAsFloat(out var aFloat) && bValues.TryGetValue(key, out var bVal) &&
bVal.TryGetValueAsFloat(out var bFloat)) {
sum += (aFloat * bFloat);
}
}
}

return new DreamValue(sum);
}

[DreamProc("values_product")]
[DreamProcParameter("Alist", Type = DreamValueTypeFlag.DreamObject)]
public static DreamValue NativeProc_values_product(NativeProc.Bundle bundle, DreamObject? src, DreamObject? usr) {
if (bundle.Arguments.Length != 1) throw new Exception("expected 1 argument");

DreamValue arg = bundle.GetArgument(0, "Alist");

float product = 1; // Default return is 1 for invalid args

if (arg.TryGetValueAsDreamList(out var list) && list.IsAssociative) {
var assocValues = list.GetAssociativeValues();
foreach (var (_,value) in assocValues) {
if(value.TryGetValueAsFloat(out var valFloat)) product *= valFloat;
}
}

return new DreamValue(product);
}

[DreamProc("values_sum")]
[DreamProcParameter("Alist", Type = DreamValueTypeFlag.DreamObject)]
public static DreamValue NativeProc_values_sum(NativeProc.Bundle bundle, DreamObject? src, DreamObject? usr) {
if (bundle.Arguments.Length != 1) throw new Exception("expected 1 argument");

DreamValue arg = bundle.GetArgument(0, "Alist");

float sum = 0; // Default return is 0 for invalid args

if (arg.TryGetValueAsDreamList(out var list) && list.IsAssociative) {
var assocValues = list.GetAssociativeValues();
foreach (var (_,value) in assocValues) {
if(value.TryGetValueAsFloat(out var valFloat)) sum += valFloat;
}
}

return new DreamValue(sum);
}

[DreamProc("view")]
[DreamProcParameter("Dist", Type = DreamValueTypeFlag.Float, DefaultValue = 5)]
[DreamProcParameter("Center", Type = DreamValueTypeFlag.DreamObject)]
Expand Down
Loading