#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 Random(65536) - 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)) { sortings[] = filterSorting; } else { 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)) { ret[] = obj; if(realLimit && realLimit <= GetLength(ret)) { return ret; } } } SortObjects(ret, sortings); if(GetLength(sortings) > 0 && limit) { SetLength(ret, limit); } return ret; }