summaryrefslogtreecommitdiffstats
path: root/DTFilterObjects.c
diff options
context:
space:
mode:
Diffstat (limited to 'DTFilterObjects.c')
-rw-r--r--DTFilterObjects.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/DTFilterObjects.c b/DTFilterObjects.c
new file mode 100644
index 0000000..77db745
--- /dev/null
+++ b/DTFilterObjects.c
@@ -0,0 +1,318 @@
+#strict 2
+
+// see C4FindObject.h
+static const C4SO_First = 100;
+static const C4SO_Last = 200;
+
+global func CheckObjectFilter(array filter, object obj)
+{
+ obj = obj || this;
+
+ if(filter[0] == C4FO_Action)
+ {
+ return obj->GetAction() == filter[1];
+ }
+ else if(filter[0] == C4FO_ActionTarget)
+ {
+ return obj->GetActionTarget(filter[2]) == filter[1];
+ }
+ else if(filter[0] == C4FO_And)
+ {
+ return CheckObject(filter, obj, 1);
+ }
+ else if(filter[0] == C4FO_AnyContainer)
+ {
+ return obj->Contained();
+ }
+ else if(filter[0] == C4FO_AtPoint)
+ {
+ var x = filter[1], y = filter[2];
+ var shape = GetShape(obj);
+ shape[0] += obj->GetX();
+ shape[1] += obj->GetY();
+
+ return InRect([x, y], shape);
+ }
+ else if(filter[0] == C4FO_AtRect)
+ {
+ var shape = GetShape(obj);
+ shape[0] += obj->GetX();
+ shape[1] += obj->GetY();
+
+ return shape[0] + shape[2] > filter[1] && shape[0] < filter[1] + filter[3] && shape[1] + shape[3] > filter[2] && shape[1] < filter[2] + filter[4];
+ }
+ else if(filter[0] == C4FO_Category)
+ {
+ return obj->GetCategory() & filter[1];
+ }
+ else if(filter[0] == C4FO_Container)
+ {
+ return obj->Contained() == filter[1];
+ }
+ else if(filter[0] == C4FO_Controller)
+ {
+ return obj->GetController() == filter[1];
+ }
+ else if(filter[0] == C4FO_Distance)
+ {
+ return ((obj->GetX() - filter[1])**2 + (obj->GetY() - filter[2])**2) <= filter[3]**2;
+ }
+ else if(filter[0] == C4FO_Exclude)
+ {
+ return obj != filter[1];
+ }
+ else if(filter[0] == C4FO_Func)
+ {
+ var args = CreateArray(GetLength(filter) - 2);
+ for(var i = 2; i < GetLength(filter); ++i)
+ {
+ args[i - 2] = filter[i];
+ }
+
+ return obj->CallA(filter[1], args, true);
+ }
+ else if(filter[0] == C4FO_ID)
+ {
+ return obj->GetID() == filter[1];
+ }
+ else if(filter[0] == C4FO_InRect)
+ {
+ return InRect([obj->GetX(), obj->GetY()], [filter[1], filter[2], filter[3], filter[4]]);
+ }
+ else if(filter[0] == C4FO_Layer)
+ {
+ return obj->GetObjectLayer() == filter[1];
+ }
+ else if(filter[0] == C4FO_Not)
+ {
+ return !CheckObject([filter[1]], obj);
+ }
+ else if(filter[0] == C4FO_OCF)
+ {
+ return obj->GetOCF() & filter[1];
+ }
+ else if(filter[0] == C4FO_OnLine)
+ {
+ var shape = GetShape(obj);
+ shape[0] += obj->GetX();
+ shape[1] += obj->GetY();
+
+ var x = filter[1], y = filter[2];
+ var x2 = filter[3], y2 = filter[4];
+
+
+ // shape is at the beginning or end of the line
+ if(InRect([x, y], shape) || InRect([x2, y2], shape))
+ {
+ return true;
+ }
+
+ // shape is completely left or above the line
+ if((x < shape[0] && x2 < shape[0]) || (y < shape[1] && y2 < shape[1]))
+ {
+ return false;
+ }
+
+ // shape is completely right or below the line
+ if((x >= shape[0] + shape[2] && x2 >= shape[0] + shape[2]) || (y >= shape[1] + shape[3] && y2 >= shape[1] + shape[3]))
+ {
+ return false;
+ }
+
+ // the line is actually a point and is neither left/right nor above/below, so it must be on that point
+ if (x == x2 || y == y2)
+ {
+ return true;
+ }
+
+ // Check intersection left/right
+ var xI;
+ if(x < shape[0])
+ {
+ xI = shape[0];
+ }
+ else
+ {
+ xI = shape[0] + shape[2];
+ }
+
+ var yI = y + (y2 - y) * (xI - x) / (x2 - x);
+ if(yI >= shape[1] && yI < shape[1] + shape[3])
+ {
+ return true;
+ }
+
+ // Check intersection up/down
+ if(y < shape[1])
+ {
+ yI = shape[1];
+ }
+ else
+ {
+ yI = shape[1] + shape[3];
+ }
+
+ xI = x + (x2 - x) * (yI - y) / (y2 - y);
+ return xI >= shape[0] && xI < shape[0] + shape[2];
+ }
+ else if(filter[0] == C4FO_Or)
+ {
+ for(var i = 1; i < GetLength(filter); ++i)
+ {
+ var orFilter = filter[i];
+ if(!orFilter)
+ {
+ continue;
+ }
+ if(CheckObjectFilter(orFilter, obj))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else if(filter[0] == C4FO_Owner)
+ {
+ return obj->GetOwner() == filter[1];
+ }
+ else
+ {
+ return true;
+ }
+}
+
+global func CheckObject(array filters, object obj, int filtersOffset)
+{
+ obj = obj || this;
+
+ for(var i = filtersOffset; i < GetLength(filters); ++i)
+ {
+ var filter = filters[i];
+ if(!filter)
+ {
+ continue;
+ }
+ if(!CheckObjectFilter(filter, obj))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+global func CompareObjects(object a, object b, array sorting)
+{
+ if(sorting[0] == C4SO_Reverse)
+ {
+ return CompareObjects(b, a, sorting[1]);
+ }
+ else if(sorting[0] == C4SO_Multiple)
+ {
+ return SortObjectsCallback(a, b, sorting, 1);
+ }
+ else if(sorting[0] == C4SO_Distance)
+ {
+ return ((a->GetX() - sorting[1])**2 + (a->GetY() - sorting[2])**2) - ((b->GetX() - sorting[1])**2 + (b->GetY() - sorting[2])**2);
+ }
+ else if(sorting[0] == C4SO_Random)
+ {
+ return Random65536 - Random(65536);
+ }
+ else if(sorting[0] == C4SO_Speed)
+ {
+ return (GetXDir(a, 65536)**2 + GetYDir(b, 65536)**2) - (GetXDir(b, 65536)**2 + GetYDir(b, 65536)**2);
+ }
+ else if(sorting[0] == C4SO_Mass)
+ {
+ return GetMass(a) - GetMass(b);
+ }
+ else if(sorting[0] == C4SO_Value)
+ {
+ return GetValue(a) - GetValue(b);
+ }
+ else if(sorting[0] == C4SO_Func)
+ {
+ var args = CreateArray(GetLength(sorting) - 2);
+ for(var i = 2; i < GetLength(sorting); ++i)
+ {
+ args[i - 2] = sorting[i];
+ }
+ return a->CallA(sorting[1], args, true) - b->CallA(sorting[1], args, true);
+ }
+
+ return 0;
+}
+
+global func SortObjectsCallback(object a, object b, array sortings, int offset)
+{
+ for(var i = offset; i < GetLength(sortings); ++i)
+ {
+ var ret = CompareObjects(a, b, sortings[i]);
+ if(ret != 0)
+ {
+ return ret;
+ }
+ }
+ return 0;
+}
+
+global func SortObjects(array& objects, array sortings)
+{
+ QSort(objects, GlobalCallback("SortObjectsCallback"), sortings);
+}
+
+global func FilterObjects(array objects, array filtersSortings, int limit)
+{
+ var filters = [], sortings = [];
+
+ for(var filterSorting in filtersSortings)
+ {
+ if(!filterSorting)
+ {
+ continue;
+ }
+
+ if(Inside(filterSorting[0], C4SO_First, C4SO_Last))
+ {
+ ArrayAppend(sortings, filterSorting);
+ }
+ else
+ {
+ ArrayAppend(filters, filterSorting);
+ }
+ }
+
+ var realLimit = limit;
+ if(GetLength(sortings) > 0)
+ {
+ realLimit = 0;
+ }
+
+ var ret = [];
+ for(var obj in objects)
+ {
+ if(!obj)
+ {
+ continue;
+ }
+
+ if(CheckObject(filters, obj))
+ {
+ ArrayAppend(ret, obj);
+
+ if(realLimit && realLimit <= GetLength(ret))
+ {
+ return ret;
+ }
+ }
+ }
+
+ SortObjects(ret, sortings);
+
+ if(GetLength(sortings) > 0 && limit)
+ {
+ SetLength(ret, limit);
+ }
+
+ return ret;
+} \ No newline at end of file