Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+132
View File
@@ -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;
}
}
}
};
+122
View File
@@ -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;
}