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
+66
View File
@@ -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;
}
};
+27
View File
@@ -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;
}
}
};
+44
View File
@@ -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;
}
}
+1
View File
@@ -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);
}
}
};
+356
View File
@@ -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];
}
}
};
+1
View File
@@ -0,0 +1 @@
#include "server/components/Orbit.as"
+64
View File
@@ -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];
}
};
+151
View File
@@ -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);
}
};
+600
View File
@@ -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;
}
}
+82
View File
@@ -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);
}
};
+81
View File
@@ -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];
}
}
};