348 lines
7.2 KiB
ActionScript 3
348 lines
7.2 KiB
ActionScript 3
from settings.map_lib import SystemDesc;
|
|
|
|
#section gui
|
|
from navigation.systems import get_systemCount, getSystem;
|
|
#section server-side
|
|
import SystemDesc@ getSystem(uint index) from "game_start";
|
|
import SystemDesc@ getSystem(Region@ region) from "game_start";
|
|
import uint get_systemCount() from "game_start";
|
|
#section menu
|
|
uint get_systemCount() { return 0; }
|
|
SystemDesc@ getSystem(uint index) { return null; }
|
|
SystemDesc@ getSystem(Region@ region) { return null; }
|
|
#section all
|
|
|
|
const double MAX_LINK_DISTANCE = INFINITY;
|
|
class SystemPath : Serializable {
|
|
int[] path;
|
|
SystemDesc@ goal;
|
|
SystemDesc@ origin;
|
|
double maxLinkDistance = MAX_LINK_DISTANCE;
|
|
|
|
priority_queue q;
|
|
double[] dist;
|
|
int[] previous;
|
|
bool[] visited;
|
|
|
|
SystemPath() {
|
|
}
|
|
|
|
bool get_valid() {
|
|
return path.length != 0;
|
|
}
|
|
|
|
void read(Message& msg) {
|
|
if(msg.readBit()) {
|
|
uint ind = 0;
|
|
msg >> ind;
|
|
@goal = getSystem(ind);
|
|
}
|
|
else {
|
|
@goal = null;
|
|
}
|
|
|
|
if(msg.readBit()) {
|
|
uint ind = 0;
|
|
msg >> ind;
|
|
@origin = getSystem(ind);
|
|
}
|
|
else {
|
|
@origin = null;
|
|
}
|
|
|
|
uint cnt = msg.readSmall();
|
|
path.length = cnt;
|
|
for(uint i = 0; i < cnt; ++i)
|
|
msg >> path[i];
|
|
|
|
maxLinkDistance = msg.read_float();
|
|
}
|
|
|
|
void write(Message& msg) {
|
|
if(goal !is null) {
|
|
msg.write1();
|
|
msg << goal.index;
|
|
}
|
|
else {
|
|
msg.write0();
|
|
}
|
|
|
|
if(origin !is null) {
|
|
msg.write1();
|
|
msg << origin.index;
|
|
}
|
|
else {
|
|
msg.write0();
|
|
}
|
|
|
|
uint cnt = path.length;
|
|
msg.writeSmall(cnt);
|
|
for(uint i = 0; i < cnt; ++i)
|
|
msg << path[i];
|
|
|
|
msg << float(maxLinkDistance);
|
|
}
|
|
|
|
void clear() {
|
|
@goal = null;
|
|
@origin = null;
|
|
path.length = 0;
|
|
}
|
|
|
|
uint get_pathSize() {
|
|
return path.length;
|
|
}
|
|
|
|
SystemDesc@ get_pathNode(uint index) {
|
|
if(index >= path.length)
|
|
return null;
|
|
int sysindex = path[index];
|
|
return getSystem(uint(sysindex));
|
|
}
|
|
|
|
void itLink(SystemDesc@ node, SystemDesc@ other, double distance) {
|
|
//Don't consider links over the maximum distance
|
|
if(distance > maxLinkDistance)
|
|
return;
|
|
|
|
//Don't consider already visited nodes
|
|
if(visited[other.index])
|
|
return;
|
|
|
|
//If the path through here is faster,
|
|
//run it through here instead
|
|
double pthlen = dist[node.index] + distance;
|
|
|
|
if(pthlen < dist[other.index]) {
|
|
dist[other.index] = pthlen;
|
|
previous[other.index] = int(node.index);
|
|
|
|
q.push(int(other.index), -dist[other.index]);
|
|
}
|
|
}
|
|
|
|
void itNodes(SystemDesc@ node) {
|
|
//Add adjacencies
|
|
uint ncnt = node.adjacent.length;
|
|
for(uint j = 0; j < ncnt; ++j) {
|
|
SystemDesc@ other = getSystem(node.adjacent[j]);
|
|
double dist = node.adjacentDist[j];
|
|
itLink(node, other, dist);
|
|
}
|
|
|
|
//Add wormholes
|
|
ncnt = node.wormholes.length;
|
|
for(uint j = 0; j < ncnt; ++j) {
|
|
SystemDesc@ other = getSystem(node.wormholes[j]);
|
|
itLink(node, other, 0.0);
|
|
}
|
|
}
|
|
|
|
//Run dijkstra and generate a path
|
|
bool generate(SystemDesc@ from, SystemDesc@ to, bool keepCache = false) {
|
|
@origin = from;
|
|
@goal = to;
|
|
return generate(keepCache);
|
|
}
|
|
|
|
bool generate(bool keepCache = false) {
|
|
uint cnt = systemCount;
|
|
while(!q.empty())
|
|
q.pop();
|
|
|
|
path.length = 0;
|
|
if(origin is null || goal is null)
|
|
return false;
|
|
if(origin is goal) {
|
|
path.insertLast(goal.index);
|
|
return true;
|
|
}
|
|
|
|
dist.length = cnt;
|
|
previous.length = cnt;
|
|
visited.length = cnt;
|
|
|
|
for(uint i = 0; i < cnt; ++i) {
|
|
dist[i] = INFINITY;
|
|
previous[i] = -1;
|
|
visited[i] = false;
|
|
}
|
|
|
|
dist[origin.index] = 0;
|
|
q.push(int(origin.index), 0);
|
|
|
|
//Run dijkstra
|
|
while(!q.empty()) {
|
|
//Retrieve the highest priority node
|
|
uint index = uint(q.top());
|
|
SystemDesc@ node = getSystem(index);
|
|
|
|
//Stop if all the nodes are unreachable
|
|
if(dist[index] == INFINITY)
|
|
break;
|
|
|
|
q.pop();
|
|
|
|
//Only visit nodes once
|
|
if(visited[index])
|
|
continue;
|
|
visited[index] = true;
|
|
|
|
//Check all neighbours
|
|
itNodes(node);
|
|
}
|
|
|
|
//Check if a path was found
|
|
if(previous[goal.index] == -1)
|
|
return false;
|
|
|
|
//Generate the path in reverse form
|
|
uint current = goal.index;
|
|
uint orig = origin.index;
|
|
while(current != orig) {
|
|
path.insertLast(current);
|
|
current = previous[current];
|
|
}
|
|
path.insertLast(current);
|
|
path.reverse();
|
|
|
|
if(!keepCache) {
|
|
dist.length = 0;
|
|
previous.length = 0;
|
|
visited.length = 0;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void printPath() {
|
|
if(goal is null || origin is null) {
|
|
print("Uninitialized path.");
|
|
return;
|
|
}
|
|
print(origin.name+" --> "+goal.name);
|
|
if(path.length == 0) {
|
|
print("Invalid path.");
|
|
return;
|
|
}
|
|
for(uint i = 0, cnt = path.length; i < cnt; ++i)
|
|
print(" . "+pathNode[i].name);
|
|
}
|
|
};
|
|
|
|
class TradePath : SystemPath {
|
|
Empire@ forEmpire;
|
|
bool onlyValid = true;
|
|
bool foundGate = false;
|
|
|
|
TradePath() {
|
|
}
|
|
|
|
TradePath(Empire@ emp) {
|
|
@forEmpire = emp;
|
|
}
|
|
|
|
void read(Message& msg) {
|
|
msg >> forEmpire;
|
|
msg >> onlyValid;
|
|
SystemPath::read(msg);
|
|
}
|
|
|
|
void write(Message& msg) {
|
|
msg << forEmpire;
|
|
msg << onlyValid;
|
|
SystemPath::write(msg);
|
|
}
|
|
|
|
bool canLink(SystemDesc@ node, SystemDesc@ other) {
|
|
if(node is other || forEmpire is null)
|
|
return true;
|
|
if(node.isAdjacent(other)) {
|
|
if(forEmpire.GlobalTrade)
|
|
return true;
|
|
if(node !is origin && node.object.TradeMask & forEmpire.TradeMask.value == 0)
|
|
return false;
|
|
if(other !is goal && other.object.TradeMask & forEmpire.TradeMask.value == 0)
|
|
return false;
|
|
}
|
|
else {
|
|
if(node.object.GateMask.value & forEmpire.mask == 0)
|
|
return false;
|
|
if(other.object.GateMask.value & forEmpire.mask == 0)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool get_isUsablePath() {
|
|
if(!valid)
|
|
return false;
|
|
if(forEmpire !is null) {
|
|
uint cnt = path.length;
|
|
SystemDesc@ prev = origin;
|
|
for(uint i = 0, cnt = path.length; i < cnt; ++i) {
|
|
SystemDesc@ desc = getSystem(path[i]);
|
|
if(!canLink(prev, desc))
|
|
return false;
|
|
@prev = desc;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool generate(bool keepCache = false) override {
|
|
onlyValid = true;
|
|
foundGate = false;
|
|
return SystemPath::generate(keepCache=keepCache);
|
|
}
|
|
|
|
bool generate(bool OnlyValid, bool keepCache) {
|
|
onlyValid = OnlyValid;
|
|
foundGate = false;
|
|
return SystemPath::generate(keepCache=keepCache);
|
|
}
|
|
|
|
void itLink(SystemDesc@ node, SystemDesc@ other, double distance) override {
|
|
if(forEmpire !is null && onlyValid && !canLink(node, other))
|
|
return;
|
|
SystemPath::itLink(node, other, distance);
|
|
}
|
|
|
|
void itNodes(SystemDesc@ node) override {
|
|
if(forEmpire !is null && !foundGate) {
|
|
if(node.object.GateMask.value & forEmpire.mask != 0) {
|
|
foundGate = true;
|
|
for(uint i = 0, cnt = systemCount; i < cnt; ++i) {
|
|
auto@ other = getSystem(i);
|
|
if(other is node)
|
|
continue;
|
|
if(other.object.GateMask.value & forEmpire.mask != 0)
|
|
SystemPath::itLink(node, other, 0.05);
|
|
}
|
|
}
|
|
}
|
|
SystemPath::itNodes(node);
|
|
}
|
|
};
|
|
|
|
const SystemDesc@ getClosestSystem(const vec3d& point, Empire& presence, bool trade = false) {
|
|
const SystemDesc@ best;
|
|
double bestDist = INFINITY;
|
|
for(uint i = 0, cnt = systemCount; i < cnt; ++i) {
|
|
auto@ sys = getSystem(i);
|
|
if(trade) {
|
|
if(sys.object.TradeMask & presence.TradeMask.value == 0)
|
|
continue;
|
|
}
|
|
else {
|
|
if(sys.object.PlanetsMask & presence.mask == 0)
|
|
continue;
|
|
}
|
|
double d = sys.object.position.distanceToSQ(point);
|
|
if(d < bestDist) {
|
|
@best = sys;
|
|
bestDist = d;
|
|
}
|
|
}
|
|
return best;
|
|
}
|