Files
2018-07-17 14:15:37 +02:00

601 lines
15 KiB
ActionScript

import resources;
import systems;
import planet_levels;
from resources import _tempResource;
tidy class ObjectResources : Component_Resources {
TradePath@[] resourcePaths;
Object@[] pathsActive;
Resource[] nativeResources;
Resource primaryResource;
Resource[] resources;
QueuedImport[] queuedImports;
Resources availableResources;
array<QueuedResource@> queuedExports;
int ExportDisabled = 0;
int ImportDisabled = 0;
uint ResourceModId = 0;
bool terraforming = false;
double resVanishBonus = 0.0;
ObjectResources() {
}
bool isTerraforming() {
return terraforming;
}
void getNativeResources(Player& pl, const Object& obj) {
Empire@ plEmp = pl.emp;
if(plEmp is obj.owner || pl == SERVER_PLAYER) {
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i)
yield(nativeResources[i]);
}
else {
Resource@ res = _tempResource();
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i) {
res = nativeResources[i];
@res.exportedTo = null;
if(queuedExports !is null) {
for(uint n = 0, ncnt = queuedExports.length; n < ncnt; ++n) {
QueuedResource@ q = queuedExports[n];
if(q.forEmpire is plEmp && res.id == q.id)
@res.exportedTo = q.to;
}
}
yield(res);
}
}
}
uint get_nativeResourceCount() {
return nativeResources.length;
}
uint get_nativeResourceType(uint i) {
if(i >= nativeResources.length)
return uint(-1);
return nativeResources[i].type.id;
}
int get_nativeResourceId(uint i) {
if(i >= nativeResources.length)
return -1;
return nativeResources[i].id;
}
uint get_nativeResourceTotalLevel() const {
uint level = 0;
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i)
level += nativeResources[i].type.level;
return level;
}
bool get_nativeResourceUsable(uint i) {
if(i >= nativeResources.length)
return false;
return nativeResources[i].usable;
}
uint get_primaryResourceType() const {
if(primaryResource.type is null)
return uint(-1);
return primaryResource.type.id;
}
uint get_primaryResourceLevel() const {
if(primaryResource.type is null)
return 0;
return primaryResource.type.level;
}
uint get_primaryResourceLimitLevel(const Object& obj) const {
if(primaryResource.type is null)
return 0;
if(primaryResource.type.limitlessLevel)
return getMaxPlanetLevel(obj.levelChain);
return primaryResource.type.level;
}
int get_primaryResourceId() const {
return primaryResource.id;
}
bool get_primaryResourceUsable() const {
return primaryResource.usable;
}
bool get_primaryResourceLocked() const {
return primaryResource.locked;
}
bool get_primaryResourceExported() const {
return primaryResource.exportedTo !is null;
}
bool get_nativeResourceLocked(Player& pl, Object& obj, uint i) {
Empire@ forEmp = pl.emp;
if(pl == SERVER_PLAYER)
@forEmp = obj.owner;
if(i >= nativeResources.length)
return false;
auto@ r = nativeResources[i];
if(forEmp is obj.owner)
return r.locked;
for(uint i = 0, cnt = queuedExports.length; i < cnt; ++i) {
QueuedResource@ q = queuedExports[i];
if(q.forEmpire is forEmp && r.id == q.id)
return q.locked;
}
return false;
}
float get_resourceVanishRate() const {
return 1.f / (1.f + resVanishBonus);
}
uint getTradedResourceCount() const {
uint tradedNative = 0;
uint usableNative = 0;
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i) {
if(!nativeResources[i].usable)
continue;
++usableNative;
if(nativeResources[i].exportedTo !is null)
++tradedNative;
}
return (resources.length - (usableNative - tradedNative)) + tradedNative;
}
Object@ get_nativeResourceDestination(Player& pl, const Object& obj, uint i) {
if(i >= nativeResources.length)
return null;
Empire@ emp = pl.emp;
Resource@ r = nativeResources[i];
//Find the current export
if(r.exportedTo !is null && (emp is obj.owner || pl == SERVER_PLAYER))
return r.exportedTo;
//Try to find a queued export
for(uint i = 0, cnt = queuedExports.length; i < cnt; ++i) {
QueuedResource@ q = queuedExports[i];
if(q.forEmpire is emp && r.id == q.id)
return q.to;
}
return null;
}
Object@ getNativeResourceDestination(const Object& obj, Empire@ emp, uint i) {
if(i >= nativeResources.length)
return null;
Resource@ r = nativeResources[i];
//Find the current export
if(r.exportedTo !is null && emp is obj.owner)
return nativeResources[i].exportedTo;
//Try to find a queued export
for(uint i = 0, cnt = queuedExports.length; i < cnt; ++i) {
QueuedResource@ q = queuedExports[i];
if(q.forEmpire is emp && r.id == q.id)
return q.to;
}
return null;
}
uint getNativeIndex(int id) {
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i) {
if(nativeResources[i].id == id)
return i;
}
return uint(-1);
}
string getDisabledReason(Object& obj, int id) {
uint index = getNativeIndex(id);
if(index >= nativeResources.length)
return "Not present";
auto@ r = nativeResources[index];
if(!r.type.exportable)
return "";
auto@ to = r.exportedTo;
if(ExportDisabled != 0)
return locale::EXPBLOCK_DISABLED;
if((to !is null && to.region is null) || obj.region is null)
return locale::EXPBLOCK_DEEPSPACE;
if(!obj.owner.valid) {
if(obj.isAsteroid)
return locale::EXPBLOCK_UNMINED;
else if(obj.isPlanet)
return locale::EXPBLOCK_UNCOLONIZED;
else
return locale::EXPBLOCK_UNOWNED;
}
if(to !is null && obj.owner !is to.owner)
return locale::EXPBLOCK_UNOWNED;
if(obj.hasSurfaceComponent) {
if(obj.population < 1.0)
return format(locale::EXPBLOCK_POP, uint(1));
else if(obj.resourceLevel < r.type.level)
return format(locale::EXPBLOCK_LOWLEVEL, r.type.level);
else if(obj.population < getPlanetLevelRequiredPop(obj, r.type.level))
return format(locale::EXPBLOCK_POP, uint(getPlanetLevelRequiredPop(obj, r.type.level)));
}
if(to !is null) {
//NOTE: Approximation of trade rules
auto@ src = obj.region;
auto@ dst = to.region;
if(src !is null && dst !is null && src !is dst &&
src.getTerritory(obj.owner) !is dst.getTerritory(obj.owner))
return locale::EXPBLOCK_DISCONNECTED;
}
if(!r.usable)
return locale::EXPBLOCK_UNUSABLE;
return "";
}
void getAvailableResources() {
for(uint i = 0, cnt = resources.length; i < cnt; ++i)
yield(resources[i]);
}
Object@ get_availableResourceOrigin(uint index) const {
if(index >= resources.length)
return null;
return resources[index].origin;
}
void getImportedResources(const Object& obj) {
for(uint i = 0, cnt = resources.length; i < cnt; ++i)
if(resources[i].origin is null || obj !is resources[i].origin)
yield(resources[i]);
}
bool get_hasAutoImports(Player& pl, Object& obj) {
for(uint i = 0, cnt = queuedImports.length; i < cnt; ++i)
if(queuedImports[i].origin is null && pl.emp is queuedImports[i].forEmpire)
return true;
return false;
}
void getAllResources(Player& pl, const Object& obj) {
Empire@ emp = pl.emp;
if(emp is obj.owner || pl == SERVER_PLAYER) {
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i)
yield(nativeResources[i]);
for(uint i = 0, cnt = resources.length; i < cnt; ++i) {
if(obj !is resources[i].origin)
yield(resources[i]);
}
}
else {
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i)
yield(nativeResources[i]);
}
for(uint i = 0, cnt = queuedImports.length; i < cnt; ++i) {
if(queuedImports[i].forEmpire is emp)
yield(queuedImports[i]);
}
}
void getQueuedImports(Player& pl, const Object& obj) {
Empire@ emp = pl.emp;
if(queuedImports !is null) {
for(uint i = 0, cnt = queuedImports.length; i < cnt; ++i) {
if(queuedImports[i].forEmpire is emp)
yield(queuedImports[i]);
}
}
}
uint get_queuedImportCount() {
return queuedImports.length;
}
uint get_queuedImportType(Player& pl, Object& obj, uint i) {
if(pl.emp !is queuedImports[i].forEmpire)
return uint(-1);
return queuedImports[i].type.id;
}
Object@ get_queuedImportOrigin(Player& pl, Object& obj, uint i) {
if(pl.emp !is queuedImports[i].forEmpire)
return null;
return queuedImports[i].origin;
}
void getResourceAmounts() {
yield(availableResources);
}
bool hasImportedResources(const Object& obj) const {
if(resources.length == 0)
return false;
for(uint i = 0, cnt = resources.length; i < cnt; ++i) {
if(obj !is resources[i].origin)
return true;
}
return false;
}
uint getImportsOfClass(Player& pl, const Object& obj, uint clsId) const {
const ResourceClass@ cls = getResourceClass(clsId);
if(cls is null)
return 0;
uint count = 0;
Empire@ emp = pl.emp;
if(emp is obj.owner) {
for(uint i = 0, cnt = resources.length; i < cnt; ++i) {
if(resources[i].type.cls is cls)
count += 1;
}
}
for(uint i = 0, cnt = queuedImports.length; i < cnt; ++i) {
const QueuedImport@ imp = queuedImports[i];
if(imp.forEmpire is emp && imp.type.cls is cls)
count += 1;
}
return count;
}
bool get_hasAutoImports(Player& pl, const Object& obj) {
for(uint i = 0, cnt = queuedImports.length; i < cnt; ++i)
if(queuedImports[i].origin is null && pl.emp is queuedImports[i].forEmpire)
return true;
return false;
}
uint get_availableResourceCount() const {
return resources.length;
}
uint get_usableResourceCount() const {
uint amt = 0;
for(uint i = 0, cnt = resources.length; i < cnt; ++i) {
if(resources[i].usable)
amt += 1;
}
return amt;
}
uint get_availableResourceType(uint index) const {
if(index >= resources.length)
return uint(-1);
return resources[index].type.id;
}
bool get_availableResourceUsable(uint index) const {
if(index >= resources.length)
return false;
return resources[index].usable;
}
bool isResourceAvailable(uint id) const {
return availableResources.getAmount(getResource(id)) != 0;
}
uint getAvailableResourceAmount(uint id) const {
return availableResources.getAmount(getResource(id));
}
Resource@ resourceFrom(Object@ from, int id) {
for(uint i = 0, cnt = resources.length; i < cnt; ++i) {
Resource@ r = resources[i];
if(r.origin is from && r.id == id)
return r;
}
return null;
}
void setAvailableResourceVanish(Object& obj, Object@ from, int id, double vanishTime) {
Resource@ r = resourceFrom(from, id);
if(r !is null)
r.vanishTime = vanishTime;
}
bool get_exportEnabled() {
return ExportDisabled == 0;
}
bool get_importEnabled() {
return ImportDisabled == 0;
}
void clearLines(Resource@ res, TradePath@ path, Object@ from, Object@ to) {
uint cnt = path.pathSize;
if(cnt == 1) {
path.origin.object.removeTradePathing(-1, from, res.id);
}
else {
for(uint i = 0; i < cnt-1; ++i) {
SystemDesc@ node = path.pathNode[i];
SystemDesc@ next = path.pathNode[i+1];;
node.object.removeTradePathing(next.index, from, res.id);
}
}
}
void updateLines(Resource@ res, TradePath@ path, Object@ from, Object@ to) {
uint cnt = path.pathSize;
if(cnt == 1) {
path.origin.object.addTradePathing(-1, from, to, res.id, res.type.id);
}
else {
for(uint i = 0; i < cnt-1; ++i) {
SystemDesc@ node = path.pathNode[i];
SystemDesc@ next = path.pathNode[i+1];;
node.object.addTradePathing(next.index, from, to, res.id, res.type.id);
}
}
}
void resourceTick(Object& obj, double time) {
//Vanish any native resources
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i) {
Resource@ r = nativeResources[i];
if(!r.usable || obj.owner is null || !obj.owner.valid)
continue;
switch(r.type.vanishMode) {
case VM_WhenExported:
if(r.exportedTo is null)
continue;
break;
case VM_ExportedInCombat:
if(r.exportedTo is null) {
if(r.origin is null || !r.origin.inCombat)
continue;
}
else {
if(!r.exportedTo.inCombat)
continue;
}
break;
case VM_Always:
break;
case VM_Custom:
if(!r.type.shouldVanish(obj, r))
continue;
break;
default:
continue;
}
if(r.exportedTo !is null) {
float rate = r.exportedTo.resourceVanishRate;
r.vanishTime += time * rate;
r.exportedTo.setAvailableResourceVanish(obj, r.id, r.vanishTime);
}
else {
r.vanishTime += time * get_resourceVanishRate();
setAvailableResourceVanish(obj, obj, r.id, r.vanishTime);
}
}
}
void destroyObjResources(Object& obj) {
for(uint i = 0, cnt = nativeResources.length; i < cnt; ++i) {
Resource@ r = nativeResources[i];
TradePath@ path = resourcePaths[i];
if(pathsActive[i] !is null)
clearLines(r, path, r.origin, pathsActive[i]);
}
}
uint get_resourceModID() {
return ResourceModId;
}
void _readRes(Object& obj, Message& msg) {
msg >> terraforming;
resVanishBonus = msg.read_float();
availableResources.read(msg);
{
uint cnt = msg.readSmall();
nativeResources.length = cnt;
for(uint i = 0; i < cnt; ++i) {
Resource@ r = nativeResources[i];
r.read(msg);
if(r.type.vanishMode != VM_Never) {
if(r.exportedTo !is null)
r.exportedTo.setAvailableResourceVanish(obj, r.id, r.vanishTime);
else
setAvailableResourceVanish(obj, obj, r.id, r.vanishTime);
}
}
}
{
uint cnt = msg.readSmall();
resources.length = cnt;
for(uint i = 0; i < cnt; ++i)
resources[i].read(msg);
}
{
uint cnt = msg.readSmall();
queuedImports.length = cnt;
for(uint i = 0; i < cnt; ++i)
queuedImports[i].readQueued(msg);
}
{
uint cnt = msg.readSmall();
queuedExports.length = cnt;
for(uint i = 0; i < cnt; ++i) {
@queuedExports[i] = QueuedResource();
queuedExports[i].read(msg);
}
}
if(nativeResources.length != 0)
primaryResource.descFrom(nativeResources[0]);
else
primaryResource.descFrom(null);
++ResourceModId;
}
void _readPath(Object& obj, Message& msg) {
uint cnt = msg.readSmall();
if(cnt != resourcePaths.length) {
uint prev = resourcePaths.length;
resourcePaths.length = cnt;
pathsActive.length = cnt;
for(uint i = prev; i < cnt; ++i) {
@resourcePaths[i] = TradePath(obj.owner);
@pathsActive[i] = null;
}
}
for(uint i = 0; i < cnt; ++i) {
TradePath@ path = resourcePaths[i];
Resource@ r = nativeResources[i];
if(pathsActive[i] !is null)
clearLines(r, path, r.origin, pathsActive[i]);
@path.forEmpire = obj.owner;
path.read(msg);
if(path.isUsablePath) {
@pathsActive[i] = r.exportedTo;
updateLines(r, path, r.origin, r.exportedTo);
}
else {
@pathsActive[i] = null;
}
}
}
void readResourceDelta(Object& obj, Message& msg) {
if(msg.readBit())
_readRes(obj, msg);
if(msg.readBit())
_readPath(obj, msg);
}
void readResources(Object& obj, Message& msg) {
_readRes(obj, msg);
_readPath(obj, msg);
if(msg.readBit())
msg >> ImportDisabled;
else
ImportDisabled = 0;
if(msg.readBit())
msg >> ExportDisabled;
else
ExportDisabled = 0;
}
}