Files
starruler-linux/scripts/server/territories.as
T
2018-07-17 14:15:37 +02:00

201 lines
4.7 KiB
ActionScript

import systems;
Territory@ createTerritory(Empire@ emp) {
ObjectDesc tdesc;
tdesc.type = OT_Territory;
@tdesc.owner = emp;
tdesc.flags |= objNoPhysics;
tdesc.position = vec3d();
return cast<Territory>(makeObject(tdesc));
}
final class TerritoryManager {
int tid = 0;
uint sysIndex = 0;
array<int> territories(systemCount, -1);
array<Territory@> terrObjects(systemCount);
array<Territory@> tidObjects;
array<Territory@> activeTerritories;
void save(SaveFile& file) {
uint cnt = terrObjects.length;
for(uint i = 0; i < cnt; ++i)
file << terrObjects[i];
for(uint i = cnt; i < systemCount; ++i) {
int tmp = -1;
file << tmp;
}
cnt = tidObjects.length;
file << cnt;
for(uint i = 0; i < cnt; ++i)
file << tidObjects[i];
}
void load(SaveFile& file) {
uint cnt = systemCount;
for(uint i = 0; i < cnt; ++i)
file >> terrObjects[i];
file >> cnt;
tidObjects.length = cnt;
for(uint i = 0; i < cnt; ++i)
file >> tidObjects[i];
}
void finalize(Empire@ emp) {
//Map tids to actual territory objects
set_int usedTerritories;
tidObjects.length = uint(tid);
for(int i = 0; i < tid; ++i)
@tidObjects[i] = null;
//First pass: find existing objects we can reuse
for(uint i = 0, cnt = territories.length; i < cnt; ++i) {
int cur = territories[i];
if(cur != -1) {
Territory@ terr = terrObjects[i];
if(terr !is null && tidObjects[cur] is null && !usedTerritories.contains(terr.id)) {
@tidObjects[cur] = terr;
usedTerritories.insert(terr.id);
}
}
}
//Create territories that weren't found
for(int i = 0; i < tid; ++i) {
if(tidObjects[i] is null) {
@tidObjects[i] = createTerritory(emp);
activeTerritories.insertLast(tidObjects[i]);
}
}
//Second pass: assign to correct territories
for(uint i = 0, cnt = territories.length; i < cnt; ++i) {
SystemDesc@ desc = getSystem(i);
int cur = territories[i];
if(cur == -1) {
if(terrObjects[i] !is null) {
desc.object.setTerritory(emp, null);
terrObjects[i].remove(desc.object);
@terrObjects[i] = null;
}
}
else {
Territory@ prev = terrObjects[i];
Territory@ next = tidObjects[cur];
usedTerritories.insert(next.id);
if(prev !is next) {
if(prev !is null)
prev.remove(desc.object);
if(next !is null)
next.add(desc.object);
@terrObjects[i] = next;
desc.object.setTerritory(emp, next);
}
}
//Clear for next pass
territories[i] = -1;
}
//Check if any territories need to be destroyed
for(int i = activeTerritories.length - 1; i >= 0; --i) {
Territory@ terr = activeTerritories[i];
if(!usedTerritories.contains(terr.id)) {
terr.destroy();
activeTerritories.removeAt(i);
}
}
//Update system counts
if(territories.length != systemCount) {
uint oldCnt = territories.length;
territories.length = systemCount;
terrObjects.length = systemCount;
for(uint i = oldCnt; i < systemCount; ++i) {
territories[i] = -1;
@terrObjects[i] = null;
}
}
}
void search(Empire@ emp, SystemDesc@ desc, int tid) {
territories[desc.index] = tid;
for(uint i = 0, cnt = desc.adjacent.length; i < cnt; ++i) {
uint adj = desc.adjacent[i];
if(adj >= territories.length || territories[adj] == tid)
continue;
SystemDesc@ other = getSystem(adj);
if(other.object.TradeMask & emp.mask != 0)
search(emp, other, tid);
}
}
bool update(Empire@ emp, double time) {
uint sysCnt = territories.length;
if(sysIndex >= sysCnt) {
finalize(emp);
sysIndex = 0;
tid = 0;
return true;
}
uint amt = max(50.0, time * 500.0);
uint mask = emp.mask;
for(uint i = 0; i < amt && sysIndex < sysCnt; ++i) {
if(territories[sysIndex] != -1) {
++sysIndex;
continue;
}
SystemDesc@ desc = getSystem(sysIndex);
//Ignore systems we can't trade through
if(desc.object.TradeMask & mask == 0) {
++sysIndex;
continue;
}
//Do a search from this position and mark everything from it
//as the same territory
search(emp, desc, tid);
++tid;
++sysIndex;
}
return false;
}
};
ScriptThread@ thread;
array<TerritoryManager> managers;
uint index = 0;
double update(double time, ScriptThread& thread) {
if(managers[index].update(getEmpire(index), time))
index = (index+1) % managers.length;
return 0.1;
}
void init() {
if(isLoadedSave)
return;
managers.length = getEmpireCount();
@thread = ScriptThread("update", null);
}
void save(SaveFile& file) {
for(uint i = 0, cnt = managers.length; i < cnt; ++i)
managers[i].save(file);
}
void load(SaveFile& file) {
managers.length = getEmpireCount();
for(uint i = 0, cnt = managers.length; i < cnt; ++i)
managers[i].load(file);
@thread = ScriptThread("update", null);
}