Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
tidy class RegionData {
|
||||
vec3d position;
|
||||
double radius;
|
||||
};
|
||||
|
||||
tidy class RegionMap {
|
||||
planed plane;
|
||||
RegionMap@ back, front;
|
||||
array<RegionData@> regs;
|
||||
bool xSplit;
|
||||
double maxRegionSize = 0;
|
||||
|
||||
RegionMap() {
|
||||
xSplit = true;
|
||||
}
|
||||
|
||||
RegionMap(bool useXSplit) {
|
||||
xSplit = useXSplit;
|
||||
}
|
||||
|
||||
RegionData@ findClosest(const vec3d& point, double& nearest) const {
|
||||
RegionData@ closest;
|
||||
if(back !is null) {
|
||||
double dist = plane.distFromPlane(point);
|
||||
|
||||
if(dist > 0.0) {
|
||||
if(dist > -nearest)
|
||||
@closest = front.findClosest(point, nearest);
|
||||
if(dist < nearest) {
|
||||
RegionData@ c = back.findClosest(point, nearest);
|
||||
if(c !is null)
|
||||
@closest = c;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(dist < nearest)
|
||||
@closest = back.findClosest(point, nearest);
|
||||
if(dist > -nearest) {
|
||||
RegionData@ c = front.findClosest(point, nearest);
|
||||
if(c !is null)
|
||||
@closest = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i = 0, cnt = regs.length; i < cnt; ++i) {
|
||||
RegionData@ reg = regs[i];
|
||||
double dist = reg.position.distanceTo(point) - reg.radius;
|
||||
if(dist < nearest) {
|
||||
@closest = reg;
|
||||
nearest = dist;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
RegionData@ findRegion(const vec3d& point) const {
|
||||
if(back !is null) {
|
||||
double dist = plane.distFromPlane(point);
|
||||
if(dist < maxRegionSize) {
|
||||
RegionData@ region = back.findRegion(point);
|
||||
if(region !is null)
|
||||
return region;
|
||||
}
|
||||
if(dist > -maxRegionSize) {
|
||||
RegionData@ region = front.findRegion(point);
|
||||
if(region !is null)
|
||||
return region;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
for(uint i = 0, cnt = regs.length; i < cnt; ++i) {
|
||||
RegionData@ region = regs[i];
|
||||
if(point.distanceToSQ(region.position) < region.radius * region.radius)
|
||||
return region;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void addSystem(const vec3d& position, double radius) {
|
||||
RegionData dat;
|
||||
dat.position = position;
|
||||
dat.radius = radius;
|
||||
addRegion(dat);
|
||||
}
|
||||
|
||||
bool hasExisting(const vec3d& position, double radius) {
|
||||
double closest = INFINITY;
|
||||
auto@ dat = findClosest(position, closest);
|
||||
if(dat is null)
|
||||
return false;
|
||||
return dat.position.distanceToSQ(position) < radius * radius;
|
||||
}
|
||||
|
||||
void addRegion(RegionData@ region) {
|
||||
if(region.radius > maxRegionSize)
|
||||
maxRegionSize = region.radius;
|
||||
|
||||
if(back !is null) {
|
||||
if(plane.inFront(region.position))
|
||||
front.addRegion(region);
|
||||
else
|
||||
back.addRegion(region);
|
||||
}
|
||||
else {
|
||||
regs.insertLast(region);
|
||||
//Once we have enough regions, split into two nodes
|
||||
if(regs.length > 4) {
|
||||
//TODO: Decide a better middle point (median, rather than mean)
|
||||
vec3d avg;
|
||||
for(uint i = 0, cnt = regs.length; i < cnt; ++i)
|
||||
avg += regs[i].position;
|
||||
avg /= double(regs.length);
|
||||
|
||||
if(xSplit)
|
||||
plane = planed(avg, vec3d_front());
|
||||
else
|
||||
plane = planed(avg, vec3d_right());
|
||||
|
||||
@back = RegionMap(!xSplit);
|
||||
@front = RegionMap(!xSplit);
|
||||
|
||||
for(uint i = 0, cnt = regs.length; i < cnt; ++i)
|
||||
addRegion(regs[i]);
|
||||
regs.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
import abilities;
|
||||
|
||||
export findEnemy, doesAutoTarget;
|
||||
export findAlliedFleet;
|
||||
export findCastable;
|
||||
|
||||
Object@ findEnemy(Object@ origin, Object@ obj, Empire@ emp, const vec3d& around, double area = -1.0, int depth = 3, bool ignoreSecondary = false) {
|
||||
double areaSQ = area * area;
|
||||
if(obj is origin && origin.isShip) {
|
||||
Ship@ ship = cast<Ship>(origin);
|
||||
Object@ targ = ship.blueprint.getCombatTarget();
|
||||
if(targ is null)
|
||||
@targ = ship.getLastHitBy();
|
||||
if(targ !is null) {
|
||||
if(targ.isVisibleTo(emp)) {
|
||||
if(ignoreSecondary) {
|
||||
if(targ.isShip && targ.hasSupportAI)
|
||||
@targ = cast<Ship>(targ).Leader;
|
||||
}
|
||||
if(targ !is null) {
|
||||
if((!ignoreSecondary || (!targ.isPlanet && !targ.isColonyShip && !targ.isCivilian && targ.owner !is null && (targ.owner.major || !emp.major)))
|
||||
&& doesAutoTarget(origin, targ)) {
|
||||
if(area < 0 || targ.position.distanceToSQ(around) < areaSQ)
|
||||
return targ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < TARGET_COUNT; ++i) {
|
||||
Object@ targ = obj.targets[i];
|
||||
if(targ.isVisibleTo(emp)) {
|
||||
if(ignoreSecondary) {
|
||||
if(targ.isShip && targ.hasSupportAI)
|
||||
@targ = cast<Ship>(targ).Leader;
|
||||
if(targ is null)
|
||||
continue;
|
||||
}
|
||||
if((!ignoreSecondary || (!targ.isPlanet && !targ.isColonyShip && !targ.isCivilian && targ.owner !is null && (targ.owner.major || !emp.major)))
|
||||
&& doesAutoTarget(origin, targ)) {
|
||||
if(area < 0 || targ.position.distanceToSQ(around) < areaSQ)
|
||||
return targ;
|
||||
}
|
||||
}
|
||||
if(depth > 1) {
|
||||
@targ = findEnemy(origin, targ, emp, around, area, depth - 1, ignoreSecondary);
|
||||
if(targ !is null)
|
||||
return targ;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool doesAutoTarget(Object@ from, Object@ to) {
|
||||
Ship@ ship = cast<Ship>(from);
|
||||
if(ship !is null) {
|
||||
if(!ship.blueprint.canTarget(from, to))
|
||||
return false;
|
||||
return ship.blueprint.doesAutoTarget(from, to);
|
||||
}
|
||||
if(to.notDamageable)
|
||||
return false;
|
||||
return from.owner.isHostile(to.owner) && (to.isShip || to.isOrbital);
|
||||
}
|
||||
|
||||
Object@ findAlliedFleet(Object@ obj, Empire@ emp, const vec3d& around, double area = -1.0, int depth = 3) {
|
||||
double areaSQ = area * area;
|
||||
for(int i = 0; i < TARGET_COUNT; ++i) {
|
||||
Object@ targ = obj.targets[i];
|
||||
if(targ.owner is emp) {
|
||||
if(targ.isShip && targ.hasSupportAI)
|
||||
@targ = cast<Ship>(targ).Leader;
|
||||
if(targ.isShip && targ.hasLeaderAI) {
|
||||
if(area < 0 || targ.position.distanceToSQ(around) < areaSQ)
|
||||
return targ;
|
||||
}
|
||||
}
|
||||
if(depth > 1) {
|
||||
@targ = findAlliedFleet(targ, emp, around, area, depth - 1);
|
||||
if(targ !is null)
|
||||
return targ;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ThreadLocal<Targets@> locTargs;
|
||||
Object@ findCastable(Ability@ abl, Object@ obj = null, int depth = 3, double range = 0.0, Targets@ targs = null) {
|
||||
if(obj is null)
|
||||
@obj = abl.obj;
|
||||
if(obj is null)
|
||||
return null;
|
||||
if(range == 0.0)
|
||||
range = abl.getRange();
|
||||
if(targs is null) {
|
||||
Targets wtf(abl.targets);
|
||||
@targs = wtf;
|
||||
if(targs.length == 0)
|
||||
return null;
|
||||
targs[0].filled = true;
|
||||
}
|
||||
double areaSQ = range * range;
|
||||
for(int i = 0; i < TARGET_COUNT; ++i) {
|
||||
Object@ targ = obj.targets[i];
|
||||
if(targ.position.distanceToSQ(obj.position) <= areaSQ) {
|
||||
@targs[0].obj = targ;
|
||||
if(abl.canActivate(targs))
|
||||
return targ;
|
||||
if(targ.isShip && targ.hasSupportAI) {
|
||||
@targs[0].obj = cast<Ship>(targ).Leader;
|
||||
if(targs[0].obj !is null && abl.canActivate(targs))
|
||||
return targs[0].obj;
|
||||
}
|
||||
}
|
||||
if(depth > 1) {
|
||||
@targ = findCastable(abl, obj, depth - 1, range, targs);
|
||||
if(targ !is null)
|
||||
return targ;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user