forked from Mirrors/openclonk
added a FindLocation function in System.ocg/FindLocation.c
parent
864c5c7ea8
commit
1cd7ffec6a
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
This script contains the function FindLocation which uses a parameter-system similar to FindObject.
|
||||
This function should mainly be used for placement of objects at the start of a scenario.
|
||||
FindLocation is not guaranteed to always return a spot if a fitting spot exists, it's just best effort.
|
||||
|
||||
Examples:
|
||||
finds a tunnel spot:
|
||||
FindLocation([Loc_Tunnel()]);
|
||||
finds a floor spot but not in front of tunnel:
|
||||
FindLocation([Loc_Not(Find_Tunnel()), Loc_Wall(CNAT_Bottom)]);
|
||||
*/
|
||||
|
||||
static const LOC_INVALID = 0;
|
||||
static const LOC_SOLID = 1;
|
||||
static const LOC_INRECT = 2;
|
||||
static const LOC_TUNNEL = 3;
|
||||
static const LOC_CONDITION = 4;
|
||||
static const LOC_WALL = 5;
|
||||
static const LOC_SPACE = 6;
|
||||
static const LOC_NOT = 7;
|
||||
|
||||
global func Loc_Condition(function)
|
||||
{
|
||||
return [LOC_CONDITION, function];
|
||||
}
|
||||
|
||||
global func Loc_Not(cond)
|
||||
{
|
||||
return [LOC_NOT, cond];
|
||||
}
|
||||
|
||||
global func Loc_InRect(x, int y, int w, int h)
|
||||
{
|
||||
if (x == nil) return [LOC_INVALID];
|
||||
if (GetType(x) == C4V_PropList) return [LOC_INRECT, x];
|
||||
return [LOC_INRECT, Rectangle(x, y, w, h)];
|
||||
}
|
||||
|
||||
global func Loc_Tunnel(bool sky)
|
||||
{
|
||||
return [LOC_TUNNEL, sky ?? false];
|
||||
}
|
||||
global func Loc_Sky() { return Loc_Tunnel(true); }
|
||||
|
||||
global func Loc_Solid()
|
||||
{
|
||||
return [LOC_SOLID];
|
||||
}
|
||||
|
||||
// implies not solid
|
||||
global func Loc_Wall(int direction)
|
||||
{
|
||||
var x = 0, y = 0;
|
||||
if(direction & CNAT_Left) x = -1;
|
||||
else
|
||||
if(direction & CNAT_Right) x = 1;
|
||||
|
||||
if(direction & CNAT_Top) y = -1;
|
||||
else
|
||||
if(direction & CNAT_Bottom) y = 1;
|
||||
return [LOC_WALL, x, y, !!(direction & (CNAT_Left | CNAT_Right)), !!(direction & (CNAT_Top | CNAT_Bottom))];
|
||||
}
|
||||
|
||||
global func Loc_Space(int space, bool vertical)
|
||||
{
|
||||
return [LOC_SPACE, space, vertical];
|
||||
}
|
||||
|
||||
global func FindLocation(array flags, int repeat)
|
||||
{
|
||||
// check for are restriction
|
||||
var rect = nil;
|
||||
var xdir = 0, ydir = 0, xmod = nil, ymod = nil;
|
||||
|
||||
for (var flag in flags)
|
||||
{
|
||||
if (flags[0] == LOC_INRECT)
|
||||
{
|
||||
rect = flags[1];
|
||||
}
|
||||
else if (flags[0] == LOC_WALL)
|
||||
{
|
||||
xdir = flags[1];
|
||||
ydir = flags[2];
|
||||
xmod = flags[3];
|
||||
ymod = flags[4];
|
||||
}
|
||||
}
|
||||
rect = rect ?? Rectangle(0, 0, LandscapeWidth(), LandscapeHeight());
|
||||
|
||||
repeat = repeat ?? 5000;
|
||||
while (repeat-- > 0)
|
||||
{
|
||||
var x = RandomX(rect.x, rect.x + rect.w);
|
||||
var y = RandomX(rect.y, rect.y + rect.h);
|
||||
|
||||
// find wall-spot
|
||||
if(xdir || ydir)
|
||||
{
|
||||
var lx = xdir;
|
||||
var ly = ydir;
|
||||
if (xmod) if (Random(2)) lx *= -1;
|
||||
if (ymod) if (Random(2)) ly *= -1;
|
||||
|
||||
if (GBackSolid(x, y)) continue;
|
||||
var valid = false;
|
||||
var failsafe = 0;
|
||||
do
|
||||
{
|
||||
if (GBackSolid(x + lx, y + ly)) {valid = true; break;}
|
||||
x += lx;
|
||||
y += ly;
|
||||
} while (++failsafe < 100);
|
||||
if (!valid) continue;
|
||||
}
|
||||
|
||||
// check every flag
|
||||
var valid = true;
|
||||
for (var flag in flags)
|
||||
{
|
||||
if(FindLocationConditionCheckIsValid(flag, x, y)) continue;
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (valid)
|
||||
{
|
||||
return {x = x, y = y};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global func FindLocationConditionCheckIsValid(flag, x, y)
|
||||
{
|
||||
|
||||
if(flag[0] == LOC_NOT) return !FindLocationConditionCheckIsValid(flag[1]);
|
||||
|
||||
// area restriction
|
||||
if (flag[0] == LOC_SOLID)
|
||||
{
|
||||
if (GBackSolid(x, y)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// in front of "Tunnel"?
|
||||
if (flag[0] == LOC_TUNNEL)
|
||||
{
|
||||
if ((GetMaterial(x, y) == -1) && flag[1]) return true;
|
||||
if (GetMaterial(x, y) == Material("Tunnel")) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// custom condition call
|
||||
if (flag[0] == LOC_CONDITION)
|
||||
{
|
||||
if (Global->Call(flag[1], x, y)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// has some space?
|
||||
if (flag[0] == LOC_SPACE)
|
||||
{
|
||||
var xd = 0, yd = 0;
|
||||
if (flag[2]) yd = flag[1];
|
||||
else xd = flag[1];
|
||||
|
||||
var d1 = PathFree2(x, y, x + xd, y + yd);
|
||||
var d2 = PathFree2(x, y, x - xd, y - yd);
|
||||
var d = 0;
|
||||
if (d1) d += Distance(x, y, d1[0], d1[1]);
|
||||
if (d2) d += Distance(x, y, d2[0], d2[1]);
|
||||
if (d >= flag[1]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// invalid flag?
|
||||
return true;
|
||||
}
|
Loading…
Reference in New Issue