Skip to content

Commit

Permalink
Implements values_cut_over() and values_cut_under()
Browse files Browse the repository at this point in the history
  • Loading branch information
ike709 committed Feb 11, 2025
1 parent 435a89a commit eb0d0f4
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 0 deletions.
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)
2 changes: 2 additions & 0 deletions DMCompiler/DMStandard/_Standard.dm
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ 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
Expand Down
2 changes: 2 additions & 0 deletions OpenDreamRuntime/Procs/Native/DreamProcNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ 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);
Expand Down
78 changes: 78 additions & 0 deletions OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3108,6 +3108,84 @@ 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) {
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
}
}
}

return new DreamValue(cutCount);
}

[DreamProc("values_dot")]
[DreamProcParameter("A", Type = DreamValueTypeFlag.DreamObject)]
[DreamProcParameter("B", Type = DreamValueTypeFlag.DreamObject)]
Expand Down

0 comments on commit eb0d0f4

Please sign in to comment.