Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import abilities;
|
||||
import saving;
|
||||
|
||||
tidy class Abilities : Component_Abilities {
|
||||
array<Ability> abilities;
|
||||
|
||||
Ability@ getAbility(int id) {
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i) {
|
||||
if(abilities[i].id == id)
|
||||
return abilities[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
uint get_abilityCount() const {
|
||||
return abilities.length;
|
||||
}
|
||||
|
||||
void abilityTick(Object& obj, double time) {
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i) {
|
||||
if(!abilities[i].disabled)
|
||||
abilities[i].cooldown = max(0.0, abilities[i].cooldown - time);
|
||||
}
|
||||
}
|
||||
|
||||
void getAbilities() const {
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i)
|
||||
yield(abilities[i]);
|
||||
}
|
||||
|
||||
uint get_abilityTypes(int id) {
|
||||
Ability@ abl = getAbility(id);
|
||||
if(abl is null)
|
||||
return uint(-1);
|
||||
return abl.type.id;
|
||||
}
|
||||
|
||||
void readAbilities(Message& msg) {
|
||||
uint cnt = msg.read_uint();
|
||||
abilities.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> abilities[i];
|
||||
}
|
||||
|
||||
void readAbilityDelta(Message& msg) {
|
||||
readAbilities(msg);
|
||||
}
|
||||
|
||||
Ability@ getAbilityOfType(int type) {
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i) {
|
||||
auto@ abl = abilities[i];
|
||||
if(abl.type.id == uint(type))
|
||||
return abl;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int findAbilityOfType(int type) const {
|
||||
auto@ abl = getAbilityOfType(type);
|
||||
if(abl is null)
|
||||
return -1;
|
||||
else
|
||||
return abl.id;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import attributes;
|
||||
|
||||
tidy class Attributes : Component_Attributes {
|
||||
array<double> attributes(getEmpAttributeCount());
|
||||
|
||||
double getAttribute(Empire& emp, uint id) {
|
||||
if(id < EA_COUNT)
|
||||
return emp.attributes[id];
|
||||
return attributes[id];
|
||||
}
|
||||
|
||||
void readAttributes(Empire& emp, Message& msg) {
|
||||
msg.readAlign();
|
||||
uint cnt = 0;
|
||||
msg >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
uint index = msg.readLimited(attributes.length-1);
|
||||
|
||||
double value = 1.0;
|
||||
msg >> value;
|
||||
|
||||
attributes[index] = value;
|
||||
if(index < EA_COUNT)
|
||||
emp.attributes[index] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
import cargo;
|
||||
|
||||
tidy class Cargo : CargoStorage, Component_Cargo {
|
||||
void getCargo() {
|
||||
yield(this);
|
||||
}
|
||||
|
||||
double get_cargoCapacity() {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
double get_cargoStored() {
|
||||
return filled;
|
||||
}
|
||||
|
||||
double getCargoStored(uint typeId) {
|
||||
auto@ type = getCargoType(typeId);
|
||||
if(type is null)
|
||||
return -1.0;
|
||||
return get(type);
|
||||
}
|
||||
|
||||
uint get_cargoTypes() {
|
||||
if(types is null)
|
||||
return 0;
|
||||
return types.length;
|
||||
}
|
||||
|
||||
uint get_cargoType(uint index) {
|
||||
if(types is null)
|
||||
return uint(-1);
|
||||
if(index >= types.length)
|
||||
return uint(-1);
|
||||
return types[index].id;
|
||||
}
|
||||
|
||||
void readCargo(Message& msg) {
|
||||
msg >> this;
|
||||
}
|
||||
|
||||
void readCargoDelta(Message& msg) {
|
||||
readCargo(msg);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
import abilities;
|
||||
|
||||
tidy class EnergyManager : Component_EnergyManager {
|
||||
Mutex ablMutex;
|
||||
array<Ability> abilities;
|
||||
|
||||
Ability@ getAbility(int id) {
|
||||
Lock lck(ablMutex);
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i) {
|
||||
if(abilities[i].id == id)
|
||||
return abilities[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void getAbility(int id) const {
|
||||
Lock lck(ablMutex);
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i) {
|
||||
if(abilities[i].id == id) {
|
||||
yield(abilities[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getAbilityOfType(uint id) const {
|
||||
Lock lck(ablMutex);
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i) {
|
||||
if(abilities[i].type.id == id) {
|
||||
yield(abilities[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint get_abilityCount() const {
|
||||
return abilities.length;
|
||||
}
|
||||
|
||||
void abilityTick(Object& obj, double time) {
|
||||
Lock lck(ablMutex);
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i) {
|
||||
if(!abilities[i].disabled)
|
||||
abilities[i].cooldown = max(0.0, abilities[i].cooldown - time);
|
||||
}
|
||||
}
|
||||
|
||||
void getAbilities() const {
|
||||
Lock lck(ablMutex);
|
||||
for(uint i = 0, cnt = abilities.length; i < cnt; ++i)
|
||||
yield(abilities[i]);
|
||||
}
|
||||
|
||||
uint get_abilityTypes(int id) {
|
||||
Lock lck(ablMutex);
|
||||
Ability@ abl = getAbility(id);
|
||||
if(abl is null)
|
||||
return uint(-1);
|
||||
return abl.type.id;
|
||||
}
|
||||
|
||||
void readAbilities(Message& msg) {
|
||||
Lock lck(ablMutex);
|
||||
uint cnt = msg.read_uint();
|
||||
abilities.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> abilities[i];
|
||||
}
|
||||
|
||||
void readAbilityDelta(Message& msg) {
|
||||
Lock lck(ablMutex);
|
||||
readAbilities(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "server/components/FleetManager.as"
|
||||
@@ -0,0 +1,123 @@
|
||||
import influence;
|
||||
import double getInfluenceIncome(int stock, int stored, double factor) from "influence_global";
|
||||
import double getInfluenceEfficiency(int stock, int stored) from "influence_global";
|
||||
import double getInfluencePercentage(Empire& emp) from "influence_global";
|
||||
import double getInfluenceStorage(int stock) from "influence_global";
|
||||
|
||||
tidy class InfluenceManager : Component_InfluenceManager {
|
||||
Mutex inflMtx;
|
||||
Mutex cardMtx;
|
||||
|
||||
int influence = 0;
|
||||
int influenceIncome = 0;
|
||||
double inflFactor = 1.0;
|
||||
array<InfluenceCard@> cards;
|
||||
|
||||
DiplomacyEdict edict;
|
||||
|
||||
int get_Influence() {
|
||||
return influence;
|
||||
}
|
||||
|
||||
int getInfluenceStock() {
|
||||
return max(influenceIncome, 0);
|
||||
}
|
||||
|
||||
double get_InfluenceIncome() {
|
||||
return getInfluenceIncome(max(influenceIncome,0), influence, inflFactor);
|
||||
}
|
||||
|
||||
double get_InfluenceEfficiency() {
|
||||
return getInfluenceEfficiency(max(influenceIncome,0), influence);
|
||||
}
|
||||
|
||||
double get_InfluencePercentage(Empire& emp) {
|
||||
return getInfluencePercentage(emp);
|
||||
}
|
||||
|
||||
double get_InfluenceCap() {
|
||||
return getInfluenceStorage(max(influenceIncome,0));
|
||||
}
|
||||
|
||||
double get_InfluenceFactor() {
|
||||
return inflFactor;
|
||||
}
|
||||
|
||||
uint getEdictType() {
|
||||
return edict.type;
|
||||
}
|
||||
|
||||
Empire@ getEdictEmpire() {
|
||||
return edict.empTarget;
|
||||
}
|
||||
|
||||
Object@ getEdictObject() {
|
||||
return edict.objTarget;
|
||||
}
|
||||
|
||||
uint getInfluenceCardType(int id) {
|
||||
Lock lock(cardMtx);
|
||||
for(uint i = 0, cnt = cards.length; i < cnt; ++i) {
|
||||
if(cards[i].id == id)
|
||||
return cards[i].type.id;
|
||||
}
|
||||
return uint(-1);
|
||||
}
|
||||
|
||||
int getInfluenceCardUses(int id) {
|
||||
Lock lock(cardMtx);
|
||||
for(uint i = 0, cnt = cards.length; i < cnt; ++i) {
|
||||
if(cards[i].id == id)
|
||||
return cards[i].uses;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getInfluenceCardQuality(int id) {
|
||||
Lock lock(cardMtx);
|
||||
for(uint i = 0, cnt = cards.length; i < cnt; ++i) {
|
||||
if(cards[i].id == id)
|
||||
return cards[i].quality;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void getInfluenceCard(int id) {
|
||||
Lock lock(cardMtx);
|
||||
for(uint i = 0, cnt = cards.length; i < cnt; ++i) {
|
||||
if(cards[i].id == id)
|
||||
yield(cards[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void influenceTick(Empire& emp, double time) {
|
||||
}
|
||||
|
||||
uint getInfluenceCardCount() {
|
||||
return cards.length;
|
||||
}
|
||||
|
||||
void getInfluenceCards() {
|
||||
Lock lock(cardMtx);
|
||||
for(uint i = 0, cnt = cards.length; i < cnt; ++i)
|
||||
yield(cards[i]);
|
||||
}
|
||||
|
||||
void readInfluenceManager(Message& msg) {
|
||||
if(msg.readBit()) {
|
||||
Lock lock(cardMtx);
|
||||
uint cnt = msg.readSmall();
|
||||
cards.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
if(cards[i] is null)
|
||||
@cards[i] = InfluenceCard();
|
||||
msg >> cards[i];
|
||||
}
|
||||
}
|
||||
|
||||
msg >> inflFactor;
|
||||
influence = msg.readSignedSmall();
|
||||
influenceIncome = msg.readSignedSmall();
|
||||
msg >> edict;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "server/components/Mover.as"
|
||||
@@ -0,0 +1,54 @@
|
||||
import notifications;
|
||||
|
||||
tidy class Notifications : Component_Notifications {
|
||||
Mutex mtx;
|
||||
array<Notification@> list;
|
||||
|
||||
uint get_notificationCount() const {
|
||||
return list.length;
|
||||
}
|
||||
|
||||
void getNotifications(uint limit, int beforeId = -1, bool reverse = true) {
|
||||
Lock lock(mtx);
|
||||
if(reverse) {
|
||||
if(beforeId == -1 || beforeId > int(list.length))
|
||||
beforeId = list.length;
|
||||
if(beforeId == 0)
|
||||
return;
|
||||
for(int i = beforeId - 1; i >= 0; --i) {
|
||||
Notification@ n = list[i];
|
||||
yieldNotification(n);
|
||||
if(--limit == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int cnt = list.length;
|
||||
if(beforeId == -1 || beforeId > cnt)
|
||||
beforeId = 0;
|
||||
if(beforeId >= cnt)
|
||||
return;
|
||||
for(int i = beforeId; i < cnt; ++i) {
|
||||
Notification@ n = list[i];
|
||||
yieldNotification(n);
|
||||
if(--limit == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readNotifications(Message& msg, bool delta) {
|
||||
Lock lock(mtx);
|
||||
uint cnt = 0;
|
||||
msg >> cnt;
|
||||
if(!delta)
|
||||
list.length = 0;
|
||||
list.reserve(list.length + cnt);
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
uint type = msg.read_uint();
|
||||
Notification@ n = createNotification(type);
|
||||
msg >> n;
|
||||
list.insertLast(n);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,356 @@
|
||||
import ftl;
|
||||
import resources;
|
||||
|
||||
tidy class ColonizationEvent : Serializable {
|
||||
Object@ from;
|
||||
Object@ to;
|
||||
|
||||
void write(Message& msg) {
|
||||
msg << from;
|
||||
msg << to;
|
||||
}
|
||||
|
||||
void read(Message& msg) {
|
||||
msg >> from;
|
||||
msg >> to;
|
||||
}
|
||||
};
|
||||
|
||||
tidy class ObjectManager : Component_ObjectManager {
|
||||
ReadWriteMutex plMutex;
|
||||
Planet@[] planets;
|
||||
Asteroid@[] asteroids;
|
||||
Orbital@[] Orbitals;
|
||||
|
||||
Mutex flingMutex;
|
||||
Object@[] flingBeacons;
|
||||
|
||||
Mutex gateMutex;
|
||||
Object@[] gates;
|
||||
|
||||
Mutex artifMutex;
|
||||
Artifact@[] artifacts;
|
||||
|
||||
ColonizationEvent@[] colonizations;
|
||||
ColonizationEvent@[] queuedAutoColonizations;
|
||||
|
||||
AutoImportDesc[] autoImports;
|
||||
|
||||
ReadWriteMutex defenseMtx;
|
||||
array<Object@> defenseObjects;
|
||||
set_int defenseSet;
|
||||
|
||||
double defenseRate = 0;
|
||||
double defenseStorage = 0;
|
||||
double defenseStored = 0;
|
||||
double localDefenseRate = 0;
|
||||
|
||||
void getPlanets() {
|
||||
ReadLock lock(plMutex);
|
||||
for(uint i = 0, cnt = planets.length; i < cnt; ++i)
|
||||
yield(planets[i]);
|
||||
}
|
||||
|
||||
void getAutoImports() {
|
||||
ReadLock lock(plMutex);
|
||||
for(uint i = 0, cnt = autoImports.length; i < cnt; ++i) {
|
||||
if(!autoImports[i].handled)
|
||||
yield(autoImports[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint get_planetCount() {
|
||||
return planets.length;
|
||||
}
|
||||
|
||||
Planet@ get_planetList(uint index) {
|
||||
ReadLock lock(plMutex);
|
||||
if(index >= planets.length)
|
||||
return null;
|
||||
return planets[index];
|
||||
}
|
||||
|
||||
uint get_orbitalCount() {
|
||||
return Orbitals.length;
|
||||
}
|
||||
|
||||
Orbital@ get_orbitals(uint index) {
|
||||
ReadLock lock(plMutex);
|
||||
if(index >= Orbitals.length)
|
||||
return null;
|
||||
return Orbitals[index];
|
||||
}
|
||||
|
||||
Orbital@ getClosestOrbital(uint type, const vec3d& position) {
|
||||
ReadLock lock(plMutex);
|
||||
Orbital@ closest;
|
||||
double closestDist = INFINITY;
|
||||
for(uint i = 0, cnt = Orbitals.length; i < cnt; ++i) {
|
||||
Orbital@ orb = Orbitals[i];
|
||||
if(orb.coreModule == type) {
|
||||
double d = orb.position.distanceToSQ(position);
|
||||
if(d < closestDist) {
|
||||
closestDist = d;
|
||||
@closest = orb;
|
||||
}
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
bool isFlingBeacon(Object@ obj) {
|
||||
Lock lock(flingMutex);
|
||||
for(uint i = 0, cnt = flingBeacons.length; i < cnt; ++i)
|
||||
if(flingBeacons[i] is obj)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void getAsteroids() {
|
||||
ReadLock lock(plMutex);
|
||||
for(uint i = 0, cnt = asteroids.length; i < cnt; ++i)
|
||||
yield(asteroids[i]);
|
||||
}
|
||||
|
||||
void getFlingBeacons() {
|
||||
Lock lock(flingMutex);
|
||||
for(uint i = 0, cnt = flingBeacons.length; i < cnt; ++i)
|
||||
yield(flingBeacons[i]);
|
||||
}
|
||||
|
||||
void getStargates() {
|
||||
Lock lock(gateMutex);
|
||||
for(uint i = 0, cnt = gates.length; i < cnt; ++i)
|
||||
yield(gates[i]);
|
||||
}
|
||||
|
||||
void getArtifacts() {
|
||||
Lock lock(artifMutex);
|
||||
for(uint i = 0, cnt = artifacts.length; i < cnt; ++i)
|
||||
yield(artifacts[i]);
|
||||
}
|
||||
|
||||
void getOrbitals() {
|
||||
ReadLock lock(plMutex);
|
||||
for(uint i = 0, cnt = Orbitals.length; i < cnt; ++i)
|
||||
yield(Orbitals[i]);
|
||||
}
|
||||
|
||||
void getQueuedColonizations(Empire& emp) {
|
||||
ReadLock lock(plMutex);
|
||||
for(uint i = 0, cnt = queuedAutoColonizations.length; i < cnt; ++i) {
|
||||
auto@ q = queuedAutoColonizations[i];
|
||||
if(q.to.owner !is emp && q.from is null)
|
||||
yield(q.to);
|
||||
}
|
||||
for(uint i = 0, cnt = colonizations.length; i < cnt; ++i) {
|
||||
if(colonizations[i].to.owner !is emp)
|
||||
yield(colonizations[i].to);
|
||||
}
|
||||
}
|
||||
|
||||
bool get_hasFlingBeacons() {
|
||||
return flingBeacons.length != 0;
|
||||
}
|
||||
|
||||
Object@ getFlingBeacon(vec3d position) {
|
||||
Lock lock(flingMutex);
|
||||
for(uint i = 0, cnt = flingBeacons.length; i < cnt; ++i) {
|
||||
if(flingBeacons[i].position.distanceToSQ(position) < FLING_BEACON_RANGE_SQ)
|
||||
return flingBeacons[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Object@ getClosestFlingBeacon(vec3d position) {
|
||||
Lock lock(flingMutex);
|
||||
Object@ nearest;
|
||||
double dist = 0;
|
||||
for(uint i = 0, cnt = flingBeacons.length; i < cnt; ++i) {
|
||||
Object@ beacon = flingBeacons[i];
|
||||
double d = beacon.position.distanceToSQ(position);
|
||||
if(nearest is null || d < dist) {
|
||||
@nearest = beacon;
|
||||
dist = d;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
Object@ getClosestFlingBeacon(Object& obj) {
|
||||
Lock lock(flingMutex);
|
||||
Object@ nearest;
|
||||
double dist = 0;
|
||||
for(uint i = 0, cnt = flingBeacons.length; i < cnt; ++i) {
|
||||
Object@ beacon = flingBeacons[i];
|
||||
if(beacon is obj)
|
||||
continue;
|
||||
double d = beacon.position.distanceToSQ(obj.position);
|
||||
if(nearest is null || d < dist) {
|
||||
@nearest = beacon;
|
||||
dist = d;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
bool hasStargates() {
|
||||
return gates.length != 0;
|
||||
}
|
||||
|
||||
Object@ getStargate(vec3d position) {
|
||||
Lock lock(gateMutex);
|
||||
Object@ best;
|
||||
double bestDist = INFINITY;
|
||||
for(uint i = 0, cnt = gates.length; i < cnt; ++i) {
|
||||
Object@ gate = gates[i];
|
||||
double d = gate.position.distanceToSQ(position);
|
||||
if(d < bestDist) {
|
||||
bestDist = d;
|
||||
@best = gate;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
bool isDefending(Object@ obj) {
|
||||
if(obj is null)
|
||||
return false;
|
||||
ReadLock lck(defenseMtx);
|
||||
return defenseSet.contains(obj.id);
|
||||
}
|
||||
|
||||
bool get_hasDefending() {
|
||||
return defenseObjects.length > 0;
|
||||
}
|
||||
|
||||
void getDefending() {
|
||||
ReadLock lck(defenseMtx);
|
||||
for(uint i = 0, cnt = defenseObjects.length; i < cnt; ++i)
|
||||
yield(defenseObjects[i]);
|
||||
}
|
||||
|
||||
void setDefending(Object@ obj, bool value) {
|
||||
if(obj is null)
|
||||
return;
|
||||
WriteLock lck(defenseMtx);
|
||||
if(value) {
|
||||
if(defenseSet.contains(obj.id))
|
||||
return;
|
||||
|
||||
defenseSet.insert(obj.id);
|
||||
defenseObjects.insertLast(obj);
|
||||
}
|
||||
else {
|
||||
if(!defenseSet.contains(obj.id))
|
||||
return;
|
||||
|
||||
defenseSet.erase(obj.id);
|
||||
defenseObjects.remove(obj);
|
||||
}
|
||||
}
|
||||
|
||||
double get_globalDefenseRate() {
|
||||
return defenseRate + localDefenseRate;
|
||||
}
|
||||
|
||||
double get_globalDefenseStorage() {
|
||||
return defenseStorage;
|
||||
}
|
||||
|
||||
double get_globalDefenseStored() {
|
||||
return defenseStored;
|
||||
}
|
||||
|
||||
void readObjects(Message& msg) {
|
||||
WriteLock wlock(plMutex);
|
||||
|
||||
if(msg.readBit()) {
|
||||
msg >> defenseRate;
|
||||
msg >> localDefenseRate;
|
||||
msg >> defenseStorage;
|
||||
msg >> defenseStored;
|
||||
}
|
||||
|
||||
if(msg.readBit()) {
|
||||
uint cnt = 0;
|
||||
msg >> cnt;
|
||||
planets.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> planets[i];
|
||||
|
||||
msg >> cnt;
|
||||
asteroids.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> asteroids[i];
|
||||
|
||||
msg >> cnt;
|
||||
Orbitals.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> Orbitals[i];
|
||||
|
||||
{
|
||||
Lock lock(flingMutex);
|
||||
msg >> cnt;
|
||||
flingBeacons.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> flingBeacons[i];
|
||||
}
|
||||
|
||||
{
|
||||
Lock lock(gateMutex);
|
||||
msg >> cnt;
|
||||
gates.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> gates[i];
|
||||
}
|
||||
|
||||
{
|
||||
Lock lock(artifMutex);
|
||||
msg >> cnt;
|
||||
artifacts.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> artifacts[i];
|
||||
}
|
||||
|
||||
{
|
||||
ReadLock lock(defenseMtx);
|
||||
msg >> cnt;
|
||||
defenseObjects.length = cnt;
|
||||
defenseSet.clear();
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
msg >> defenseObjects[i];
|
||||
if(defenseObjects[i] !is null)
|
||||
defenseSet.insert(defenseObjects[i].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(msg.readBit()) {
|
||||
uint cnt = 0;
|
||||
msg >> cnt;
|
||||
colonizations.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
if(colonizations[i] is null)
|
||||
@colonizations[i] = ColonizationEvent();
|
||||
msg >> colonizations[i];
|
||||
}
|
||||
|
||||
msg >> cnt;
|
||||
queuedAutoColonizations.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
if(queuedAutoColonizations[i] is null)
|
||||
@queuedAutoColonizations[i] = ColonizationEvent();
|
||||
msg >> queuedAutoColonizations[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(msg.readBit()) {
|
||||
uint cnt = 0;
|
||||
msg >> cnt;
|
||||
autoImports.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i)
|
||||
msg >> autoImports[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
#include "server/components/Orbit.as"
|
||||
@@ -0,0 +1,64 @@
|
||||
import random_events;
|
||||
|
||||
tidy class RandomEvents : Component_RandomEvents {
|
||||
Mutex mtx;
|
||||
array<CurrentEvent> events;
|
||||
|
||||
CurrentEvent@ getEventByID(int id) {
|
||||
for(uint i = 0, cnt = events.length; i < cnt; ++i) {
|
||||
if(events[i].id == id)
|
||||
return events[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int get_currentEventID() {
|
||||
if(events.length == 0)
|
||||
return -1;
|
||||
Lock lck(mtx);
|
||||
if(events.length == 0)
|
||||
return -1;
|
||||
return events[0].id;
|
||||
}
|
||||
|
||||
bool hasCurrentEvents() {
|
||||
return events.length != 0;
|
||||
}
|
||||
|
||||
void getCurrentEvents() {
|
||||
Lock lck(mtx);
|
||||
for(uint i = 0, cnt = events.length; i < cnt; ++i)
|
||||
yield(events[i]);
|
||||
}
|
||||
|
||||
void getEvent(int id) {
|
||||
Lock lck(mtx);
|
||||
auto@ evt = getEventByID(id);
|
||||
if(evt !is null)
|
||||
yield(evt);
|
||||
}
|
||||
|
||||
void chooseEventOption(Empire& emp, int evtId, uint optId) {
|
||||
Lock lck(mtx);
|
||||
for(uint i = 0, cnt = events.length; i < cnt; ++i) {
|
||||
if(events[i].id == evtId) {
|
||||
events.removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void readEvents(Message& msg) {
|
||||
if(!msg.readBit()) {
|
||||
if(events.length != 0) {
|
||||
Lock lck(mtx);
|
||||
events.length = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Lock lck(mtx);
|
||||
events.length = msg.readSmall();
|
||||
for(uint i = 0, cnt = events.length; i < cnt; ++i)
|
||||
msg >> events[i];
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,151 @@
|
||||
import research;
|
||||
|
||||
tidy class ResearchGrid : Component_ResearchGrid {
|
||||
ReadWriteMutex mtx;
|
||||
|
||||
TechnologyGrid grid;
|
||||
|
||||
array<bool>@ tagUnlocks;
|
||||
|
||||
double researchRate = 0;
|
||||
double points = 0;
|
||||
double totalGenerated = 0;
|
||||
|
||||
double get_ResearchRate(Empire& emp) {
|
||||
return researchRate * ResearchEfficiency * emp.ResearchGenerationFactor;
|
||||
}
|
||||
|
||||
double get_ResearchEfficiency() {
|
||||
return 2000.0 / (2000.0 + totalGenerated);
|
||||
}
|
||||
|
||||
double get_ResearchPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
void getTechnologyNodes() {
|
||||
ReadLock lock(mtx);
|
||||
for(uint i = 0, cnt = grid.nodes.length; i < cnt; ++i)
|
||||
yield(grid.nodes[i]);
|
||||
}
|
||||
|
||||
void getTechnologyNode(int id) {
|
||||
ReadLock lock(mtx);
|
||||
for(uint i = 0, cnt = grid.nodes.length; i < cnt; ++i) {
|
||||
if(id == grid.nodes[i].id) {
|
||||
yield(grid.nodes[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TechnologyNode@ getNode(int id) {
|
||||
for(uint i = 0, cnt = grid.nodes.length; i < cnt; ++i) {
|
||||
if(grid.nodes[i].id == id)
|
||||
return grid.nodes[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void setResearchQueued(Empire& emp, int id, bool queued) {
|
||||
//PREDICTIVE
|
||||
WriteLock lock(mtx);
|
||||
auto@ node = getNode(id);
|
||||
if(node is null)
|
||||
return;
|
||||
if(node.bought)
|
||||
return;
|
||||
|
||||
node.queued = queued;
|
||||
}
|
||||
|
||||
void research(Empire& emp, int id, bool secondary = false, bool queue = false) {
|
||||
//PREDICTIVE
|
||||
WriteLock lock(mtx);
|
||||
auto@ node = getNode(id);
|
||||
if(node is null)
|
||||
return;
|
||||
if(node.bought)
|
||||
return;
|
||||
|
||||
if(queue) {
|
||||
if(node.canUnlock(emp))
|
||||
node.queued = true;
|
||||
}
|
||||
}
|
||||
|
||||
void getResearchingNodes() {
|
||||
ReadLock lock(mtx);
|
||||
for(uint i = 0, cnt = grid.nodes.length; i < cnt; ++i) {
|
||||
auto@ node = grid.nodes[i];
|
||||
if(!node.bought)
|
||||
continue;
|
||||
if(node.unlocked)
|
||||
continue;
|
||||
if(!node.unlockable)
|
||||
continue;
|
||||
yield(grid.nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void getTechnologyNode(vec2i pos) {
|
||||
ReadLock lock(mtx);
|
||||
for(uint i = 0, cnt = grid.nodes.length; i < cnt; ++i) {
|
||||
if(pos == grid.nodes[i].position) {
|
||||
yield(grid.nodes[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isTagUnlocked(int id) {
|
||||
if(tagUnlocks is null)
|
||||
return false;
|
||||
if(id < 0 || uint(id) >= tagUnlocks.length)
|
||||
return false;
|
||||
return tagUnlocks[id];
|
||||
}
|
||||
|
||||
void readResearch(Message& msg) {
|
||||
WriteLock lock(mtx);
|
||||
msg >> researchRate;
|
||||
msg >> points;
|
||||
msg >> totalGenerated;
|
||||
bool delta = msg.readBit();
|
||||
bool gridDelta = msg.readBit();
|
||||
|
||||
if(msg.readBit()) {
|
||||
uint cnt = msg.readSmall();
|
||||
if(tagUnlocks is null)
|
||||
@tagUnlocks = array<bool>(cnt, false);
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
bool unlocked = msg.readBit();
|
||||
if(i < tagUnlocks.length)
|
||||
tagUnlocks[i] = unlocked;
|
||||
}
|
||||
}
|
||||
|
||||
if(delta || gridDelta) {
|
||||
if(gridDelta) {
|
||||
msg >> grid.minPos;
|
||||
msg >> grid.maxPos;
|
||||
|
||||
uint cnt = 0;
|
||||
msg >> cnt;
|
||||
grid.nodes.length = cnt;
|
||||
}
|
||||
|
||||
for(uint i = 0, cnt = grid.nodes.length; i < cnt; ++i) {
|
||||
if(grid.nodes[i] is null)
|
||||
@grid.nodes[i] = TechnologyNode();
|
||||
if(gridDelta)
|
||||
grid.nodes[i].read(msg);
|
||||
else
|
||||
grid.nodes[i].readStatus(msg);
|
||||
}
|
||||
|
||||
if(gridDelta)
|
||||
grid.regenGrid();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,232 @@
|
||||
import resources;
|
||||
|
||||
tidy class ResourceManager : Component_ResourceManager {
|
||||
Mutex budgetMutex;
|
||||
Mutex ftlMutex;
|
||||
Mutex energyMutex;
|
||||
|
||||
double Population = 0;
|
||||
|
||||
double FTL_Capacity = 0;
|
||||
double FTL_Stored = 0;
|
||||
double FTL_Income = 0;
|
||||
double FTL_Use = 0;
|
||||
|
||||
double Energy_Stored = 0;
|
||||
double Energy_Income = 0;
|
||||
double Energy_Use = 0;
|
||||
double Energy_Allocated = 0;
|
||||
|
||||
uint welfareMode = WM_Influence;
|
||||
int Budget_Total = 0;
|
||||
int Maintenance = 0;
|
||||
int PrevBudget = 0;
|
||||
int PrevMaintenance = 0;
|
||||
int Budget_Remaining = 0;
|
||||
int Budget_Forward = 0;
|
||||
int Budget_CycleId = 0;
|
||||
int Budget_Bonus = 0;
|
||||
double Budget_Cycle = 3.0 * 60.0;
|
||||
double Budget_Tick = Budget_Cycle;
|
||||
double Borrow_Rate = 1.5;
|
||||
|
||||
array<int> moneyTypes = array<int>(MoT_COUNT, 0);
|
||||
|
||||
//Population
|
||||
double get_EstTotalPopulation() const {
|
||||
return max(round(Population / 10.0), 1.0) * 10.0;
|
||||
}
|
||||
|
||||
double get_TotalPopulation() const {
|
||||
return Population;
|
||||
}
|
||||
|
||||
//FTL
|
||||
double get_FTLIncome() {
|
||||
return FTL_Income;
|
||||
}
|
||||
|
||||
double get_FTLStored() {
|
||||
return FTL_Stored;
|
||||
}
|
||||
|
||||
double get_FTLUse(const Empire& emp) {
|
||||
return FTL_Use * emp.FTLCostFactor;
|
||||
}
|
||||
|
||||
double get_FTLCapacity() {
|
||||
return FTL_Capacity;
|
||||
}
|
||||
|
||||
bool get_FTLShortage(const Empire& emp) const {
|
||||
return FTL_Stored <= 0.0001 && (FTL_Use * emp.FTLCostFactor) > FTL_Income + 0.0001;
|
||||
}
|
||||
|
||||
bool isFTLShortage(const Empire& emp, double amt) const {
|
||||
if(FTL_Use + amt <= FTL_Income + 0.0001)
|
||||
return false;
|
||||
|
||||
//Only not a shortage if we can run it for at least a minute
|
||||
double cons = (FTL_Use + amt) * emp.FTLCostFactor * 60.0;
|
||||
double have = FTL_Stored + FTL_Income * 60.0;
|
||||
return cons >= have;
|
||||
}
|
||||
|
||||
//Energy
|
||||
double get_EnergyIncome() {
|
||||
return Energy_Income;
|
||||
}
|
||||
|
||||
double get_EnergyStored() {
|
||||
return Energy_Stored;
|
||||
}
|
||||
|
||||
double get_EnergyUse() {
|
||||
return Energy_Use;
|
||||
}
|
||||
|
||||
double get_EnergyEfficiency(Empire& emp) {
|
||||
return pow(0.5, max(Energy_Stored + Energy_Allocated - emp.FreeEnergyStorage, 0.0) / config::ENERGY_EFFICIENCY_STEP);
|
||||
}
|
||||
|
||||
bool get_EnergyShortage() {
|
||||
return Energy_Stored <= 0.0001 && Energy_Use > EnergyIncome + 0.0001;
|
||||
}
|
||||
|
||||
bool isEnergyShortage(double amt) {
|
||||
if(Energy_Use + amt <= EnergyIncome + 0.0001)
|
||||
return false;
|
||||
|
||||
//Only not a shortage if we can run it for at least a minute
|
||||
double cons = (Energy_Use + amt) * 60.0;
|
||||
double have = Energy_Stored + EnergyIncome * 60.0;
|
||||
return cons >= have;
|
||||
}
|
||||
|
||||
bool consumeEnergyUse(double amt) {
|
||||
Lock lock(energyMutex);
|
||||
if(Energy_Use + amt <= EnergyIncome + 0.0001) {
|
||||
Energy_Use += amt;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Only not a shortage if we can run it for at least a minute
|
||||
double cons = (Energy_Use + amt) * 60.0;
|
||||
double have = Energy_Stored + EnergyIncome * 60.0;
|
||||
if(cons >= have)
|
||||
return false;
|
||||
|
||||
Energy_Use += amt;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Budget
|
||||
int getMoneyFromType(uint type) {
|
||||
if(type < MoT_COUNT)
|
||||
return moneyTypes[type];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_TotalBudget() {
|
||||
return Budget_Total;
|
||||
}
|
||||
|
||||
int get_MaintenanceBudget() {
|
||||
return Maintenance;
|
||||
}
|
||||
|
||||
int get_RemainingBudget() {
|
||||
return Budget_Remaining;
|
||||
}
|
||||
|
||||
int get_ForwardBudget() {
|
||||
return Budget_Forward;
|
||||
}
|
||||
|
||||
int get_BonusBudget() {
|
||||
return Budget_Bonus;
|
||||
}
|
||||
|
||||
double get_BorrowRate() {
|
||||
return Borrow_Rate;
|
||||
}
|
||||
|
||||
double get_BudgetCycle() {
|
||||
return Budget_Cycle;
|
||||
}
|
||||
|
||||
double get_BudgetTimer() {
|
||||
return Budget_Tick;
|
||||
}
|
||||
|
||||
float get_DebtFactor() {
|
||||
if(Budget_Remaining >= 0)
|
||||
return 0.f;
|
||||
if(Budget_Total < 100)
|
||||
return float(-Budget_Remaining) / 100.f;
|
||||
return float(-Budget_Remaining) / float(Budget_Total);
|
||||
}
|
||||
|
||||
int get_EstNextBudget() const {
|
||||
int budget = Budget_Total - Maintenance + Budget_Forward + Budget_Bonus;
|
||||
budget += min(Budget_Remaining - min(PrevBudget - PrevMaintenance, 0), 0);
|
||||
return budget;
|
||||
}
|
||||
|
||||
int getEstBudgetConsuming(int amount) const {
|
||||
int budget = Budget_Total - Maintenance + Budget_Forward + max(Budget_Bonus - amount, 0);
|
||||
budget += min(Budget_Remaining - amount - min(PrevBudget - PrevMaintenance, 0), 0);
|
||||
return budget;
|
||||
}
|
||||
|
||||
int get_BudgetCycleId() {
|
||||
return Budget_CycleId;
|
||||
}
|
||||
|
||||
uint get_WelfareMode() const {
|
||||
return welfareMode;
|
||||
}
|
||||
|
||||
bool canBorrow(int amount) const {
|
||||
amount = ceil(double(amount) * Borrow_Rate);
|
||||
return EstNextBudget >= amount;
|
||||
}
|
||||
|
||||
bool canPay(int amount) const {
|
||||
if(amount <= Budget_Remaining)
|
||||
return true;
|
||||
return canBorrow(amount - Budget_Remaining);
|
||||
}
|
||||
|
||||
//Networking
|
||||
void readResources(Empire& emp, Message& msg) {
|
||||
Population = msg.read_float();
|
||||
|
||||
FTL_Capacity = msg.read_float();
|
||||
FTL_Stored = msg.read_float();
|
||||
FTL_Income = msg.read_float();
|
||||
FTL_Use = msg.read_float();
|
||||
|
||||
Energy_Stored = msg.read_float();
|
||||
Energy_Income = msg.read_float();
|
||||
Energy_Use = msg.read_float();
|
||||
Energy_Allocated = msg.read_float();
|
||||
|
||||
msg >> Budget_Total;
|
||||
msg >> Maintenance;
|
||||
msg >> PrevMaintenance;
|
||||
msg >> PrevBudget;
|
||||
msg >> Budget_Remaining;
|
||||
msg >> Budget_Forward;
|
||||
msg >> Budget_Bonus;
|
||||
msg >> Budget_CycleId;
|
||||
Budget_Cycle = msg.read_float();
|
||||
Budget_Tick = msg.read_float();
|
||||
Borrow_Rate = msg.read_float();
|
||||
|
||||
for(uint i = 0; i < MoT_COUNT; ++i)
|
||||
moneyTypes[i] = msg.readSignedSmall();
|
||||
|
||||
welfareMode = msg.readLimited(WM_COUNT-1);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,600 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import statuses;
|
||||
|
||||
tidy class Statuses : Component_Statuses {
|
||||
array<Status@> statuses;
|
||||
|
||||
void getStatusEffects(Player& pl, Object& obj) {
|
||||
Empire@ plEmp = pl.emp;
|
||||
for(uint i = 0, cnt = statuses.length; i < cnt; ++i) {
|
||||
if(!statuses[i].isVisibleTo(obj, plEmp))
|
||||
continue;
|
||||
yield(statuses[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint get_statusEffectCount() {
|
||||
return statuses.length;
|
||||
}
|
||||
|
||||
uint get_statusEffectType(uint index) {
|
||||
if(index >= statuses.length)
|
||||
return uint(-1);
|
||||
return statuses[index].type.id;
|
||||
}
|
||||
|
||||
uint get_statusEffectStacks(uint index) {
|
||||
if(index >= statuses.length)
|
||||
return 0;
|
||||
return statuses[index].stacks;
|
||||
}
|
||||
|
||||
Object@ get_statusEffectOriginObject(uint index) {
|
||||
if(index >= statuses.length)
|
||||
return null;
|
||||
return statuses[index].originObject;
|
||||
}
|
||||
|
||||
Empire@ get_statusEffectOriginEmpire(uint index) {
|
||||
if(index >= statuses.length)
|
||||
return null;
|
||||
return statuses[index].originEmpire;
|
||||
}
|
||||
|
||||
uint getStatusStackCountAny(uint typeId) {
|
||||
uint count = 0;
|
||||
for(uint i = 0, cnt = statuses.length; i < cnt; ++i) {
|
||||
if(statuses[i].type.id == typeId)
|
||||
count += statuses[i].stacks;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint getStatusStackCount(uint typeId, Object@ originObject = null, Empire@ originEmpire = null) {
|
||||
uint count = 0;
|
||||
for(uint i = 0, cnt = statuses.length; i < cnt; ++i) {
|
||||
if(statuses[i].type.id == typeId && statuses[i].originObject is originObject && statuses[i].originEmpire is originEmpire)
|
||||
count += statuses[i].stacks;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool hasStatusEffect(uint typeId) {
|
||||
for(uint i = 0, cnt = statuses.length; i < cnt; ++i) {
|
||||
if(statuses[i].type.id == typeId)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void readStatuses(Message& msg) {
|
||||
uint cnt = msg.readSmall();
|
||||
statuses.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
if(statuses[i] is null)
|
||||
@statuses[i] = Status();
|
||||
msg >> statuses[i];
|
||||
}
|
||||
}
|
||||
|
||||
void readStatusDelta(Message& msg) {
|
||||
readStatuses(msg);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
import traits;
|
||||
import attitudes;
|
||||
|
||||
tidy class Traits : Component_Traits {
|
||||
array<const Trait@> traits;
|
||||
array<bool> hasTraits(getTraitCount(), false);
|
||||
|
||||
array<Attitude> attitudes;
|
||||
ReadWriteMutex attMtx;
|
||||
|
||||
bool hasTrait(uint id) {
|
||||
if(id >= hasTraits.length)
|
||||
return false;
|
||||
return hasTraits[id];
|
||||
}
|
||||
|
||||
uint get_traitCount() const {
|
||||
return traits.length;
|
||||
}
|
||||
|
||||
uint getTraitType(uint index) const {
|
||||
if(index >= traits.length)
|
||||
return uint(-1);
|
||||
return traits[index].id;
|
||||
}
|
||||
|
||||
uint getAttitudeLevel(uint id) const {
|
||||
ReadLock lck(attMtx);
|
||||
Attitude@ att;
|
||||
for(uint i = 0, cnt = attitudes.length; i < cnt; ++i) {
|
||||
if(attitudes[i].type.id == id)
|
||||
return attitudes[i].level;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void readTraits(Message& msg) {
|
||||
uint cnt = msg.readSmall();
|
||||
traits.length = cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
int id = msg.readSmall();
|
||||
@traits[i] = getTrait(id);
|
||||
hasTraits[id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint get_attitudeCount() {
|
||||
return attitudes.length;
|
||||
}
|
||||
|
||||
void getAttitudes() {
|
||||
ReadLock lck(attMtx);
|
||||
for(uint i = 0, cnt = attitudes.length; i < cnt; ++i)
|
||||
yield(attitudes[i]);
|
||||
}
|
||||
|
||||
bool hasAttitude(uint id) {
|
||||
ReadLock lck(attMtx);
|
||||
for(uint i = 0, cnt = attitudes.length; i < cnt; ++i)
|
||||
if(attitudes[i].type.id == id)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int getNextAttitudeCost(Empire& emp) {
|
||||
if(emp.FreeAttitudes > 0)
|
||||
return 0;
|
||||
return config::ATTITUDE_BASE_COST + config::ATTITUDE_INC_COST * max(int(attitudes.length)-1, 0);
|
||||
}
|
||||
|
||||
void readAttitudes(Message& msg, bool initial) {
|
||||
uint cnt = msg.readSmall();
|
||||
attitudes.length = cnt;
|
||||
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
if(msg.readBit())
|
||||
msg >> attitudes[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user