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
@@ -0,0 +1,734 @@
#include "include/resource_constants.as"
import resources;
import attributes;
from saving import SaveVersion;
//Amount of money spent in welfare that gives you one influence stock
const int MONEY_PER_INFLUENCE = 350;
//Amount of money spent in welfare that gives you one energy stock
const int MONEY_PER_ENERGY = 350;
//Amount of money spent in welfare that gives you one research stock
const int MONEY_PER_RESEARCH = 350;
//Amount of money spent in welfare that gives you one labor generation on the homeworld
const int MONEY_PER_HW_LABOR = 350;
//Amount of money spent in welfare that gives you one global defense generation
const int MONEY_PER_DEFENSE = 350;
tidy class EnergyFloat {
Empire@ forEmp;
double amount;
};
tidy class ResourceManager : Component_ResourceManager, Savable {
Mutex popMutex;
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;
array<EnergyFloat@> floatedEnergy;
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;
int Budget_CycleBonus = 0;
double Budget_Cycle = 3.0 * 60.0;
double Budget_Tick = Budget_Cycle - 0.2;
double Borrow_Rate = 1.5;
double StatRecordDelay = 5.0;
uint welfareMode = WM_Influence;
int welfareInfluence = 0, welfareEnergy = 0, welfareResearch = 0, welfareHWLabor = 0, welfareDefense = 0;
int storedWelfare = 0;
array<int> moneyTypes = array<int>(MoT_COUNT, 0);
void load(SaveFile& msg) {
msg >> Population;
msg >> FTL_Capacity;
msg >> FTL_Stored;
msg >> FTL_Income;
if(msg >= SV_0009)
msg >> FTL_Use;
msg >> Energy_Stored;
msg >> Energy_Income;
msg >> Energy_Use;
if(msg >= SV_0055)
msg >> Energy_Allocated;
msg >> Budget_Total;
msg >> Maintenance;
msg >> PrevBudget;
msg >> PrevMaintenance;
msg >> Budget_Remaining;
msg >> Budget_Forward;
msg >> Budget_CycleId;
msg >> Budget_Cycle;
msg >> Budget_Tick;
msg >> Borrow_Rate;
msg >> Budget_Bonus;
msg >> Budget_CycleBonus;
msg >> StatRecordDelay;
msg >> welfareMode;
msg >> welfareInfluence;
if(msg > SV_0003) {
msg >> welfareEnergy;
msg >> welfareResearch;
msg >> welfareHWLabor;
}
if(msg >= SV_0125)
msg >> welfareDefense;
msg >> storedWelfare;
for(uint i = 0; i < MoT_COUNT-1; ++i)
msg >> moneyTypes[i];
if(msg >= SV_0070)
msg >> moneyTypes[MoT_Vassals];
if(msg >= SV_0067) {
uint cnt = 0;
msg >> cnt;
floatedEnergy.length = cnt;
for(uint i = 0; i < cnt; ++i) {
EnergyFloat flt;
msg >> flt.forEmp;
msg >> flt.amount;
@floatedEnergy[i] = flt;
}
}
}
void save(SaveFile& msg) {
msg << Population;
msg << FTL_Capacity;
msg << FTL_Stored;
msg << FTL_Income;
msg << FTL_Use;
msg << Energy_Stored;
msg << Energy_Income;
msg << Energy_Use;
msg << Energy_Allocated;
msg << Budget_Total;
msg << Maintenance;
msg << PrevBudget;
msg << PrevMaintenance;
msg << Budget_Remaining;
msg << Budget_Forward;
msg << Budget_CycleId;
msg << Budget_Cycle;
msg << Budget_Tick;
msg << Borrow_Rate;
msg << Budget_Bonus;
msg << Budget_CycleBonus;
msg << StatRecordDelay;
msg << welfareMode;
msg << welfareInfluence;
msg << welfareEnergy;
msg << welfareResearch;
msg << welfareHWLabor;
msg << welfareDefense;
msg << storedWelfare;
for(uint i = 0; i < MoT_COUNT; ++i)
msg << moneyTypes[i];
uint cnt = floatedEnergy.length;
msg << cnt;
for(uint i = 0; i < cnt; ++i) {
msg << floatedEnergy[i].forEmp;
msg << floatedEnergy[i].amount;
}
}
//Population
double get_EstTotalPopulation() const {
return max(round(Population / 10.0), 1.0) * 10.0;
}
double get_TotalPopulation() const {
return Population;
}
void modTotalPopulation(Empire& emp, double amount) {
Lock lock(popMutex);
Population += amount;
}
//FTL
double get_FTLIncome() {
return FTL_Income;
}
double get_FTLStored() {
return FTL_Stored;
}
double get_FTLCapacity() {
return FTL_Capacity;
}
double get_FTLUse(const Empire& emp) {
return FTL_Use * emp.FTLCostFactor;
}
double consumeFTL(Empire& emp, double amount, bool consumePartial = true, bool record = true) {
if(!consumePartial && FTL_Stored < amount)
return 0.0;
Lock lock(ftlMutex);
amount = min(FTL_Stored, amount);
FTL_Stored -= amount;
if(amount > 0 && record)
emp.modAttribute(EA_FTLEnergySpent, AC_Add, amount);
return amount;
}
void modFTLCapacity(double amount) {
Lock lock(ftlMutex);
FTL_Capacity += amount;
}
void modFTLStored(double amount, bool obeyMaximum = false) {
Lock lock(ftlMutex);
if(obeyMaximum)
FTL_Stored = clamp(FTL_Stored + amount, 0.0, max(FTL_Capacity, FTL_Stored));
else
FTL_Stored = max(FTL_Stored + amount, 0.0);
}
void modFTLIncome(double amount) {
Lock lock(ftlMutex);
FTL_Income += amount;
}
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;
}
bool consumeFTLUse(Empire& emp, double amt) {
Lock lock(ftlMutex);
if(FTL_Use + amt <= FTL_Income + 0.0001) {
FTL_Use += amt;
return true;
}
//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;
if(cons >= have)
return false;
FTL_Use += amt;
return true;
}
void modFTLUse(double amount) {
Lock lock(ftlMutex);
FTL_Use += amount;
}
//Energy
double get_EnergyIncome(Empire& emp) {
return Energy_Income * emp.EnergyGenerationFactor;
}
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(Empire& emp) {
return Energy_Stored <= 0.0001 && Energy_Use > (Energy_Income * emp.EnergyGenerationFactor) + 0.0001;
}
bool isEnergyShortage(Empire& emp, double amt) {
if(Energy_Use + amt <= (Energy_Income * emp.EnergyGenerationFactor) + 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 + Energy_Income * 60.0 * emp.EnergyGenerationFactor;
return cons >= have;
}
bool consumeEnergyUse(Empire& emp, double amt) {
Lock lock(energyMutex);
if(Energy_Use + amt <= (Energy_Income * emp.EnergyGenerationFactor) + 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 + Energy_Income * 60.0 * emp.EnergyGenerationFactor;
if(cons >= have)
return false;
Energy_Use += amt;
return true;
}
double consumeEnergy(double amount, bool consumePartial = true) {
if(!consumePartial && Energy_Stored < amount)
return 0.0;
Lock lock(energyMutex);
amount = min(Energy_Stored, amount);
Energy_Stored -= amount;
for(uint i = 0, cnt = floatedEnergy.length; i < cnt && amount > 0; ++i) {
auto@ flt = floatedEnergy[i];
double take = min(flt.amount, amount);
if(take != 0) {
flt.amount -= take;
amount -= take;
flt.forEmp.modEnergyAllocated(-take);
if(flt.amount < 0.001) {
floatedEnergy.removeAt(i);
--i; --cnt;
}
}
}
return amount;
}
void addFloatedEnergy(Empire@ forEmp, double value) {
EnergyFloat flt;
@flt.forEmp = forEmp;
flt.amount = value;
floatedEnergy.insertLast(flt);
}
void modEnergyAllocated(double amount) {
Lock lock(energyMutex);
Energy_Allocated += amount;
}
void modEnergyStored(double amount) {
Lock lock(energyMutex);
Energy_Stored = max(Energy_Stored + amount, 0.0);
}
void modEnergyIncome(double amount) {
Lock lock(energyMutex);
Energy_Income += amount;
}
void modEnergyUse(double amount) {
Lock lock(energyMutex);
Energy_Use += amount;
}
//Budget
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;
}
void multBorrowPenalty(double multiply) {
Borrow_Rate = 1.0 + (Borrow_Rate - 1.0) * multiply;
}
double get_BudgetCycle() {
return Budget_Cycle;
}
double get_BudgetTimer() {
return Budget_Tick;
}
float get_DebtFactor() {
auto remaining = Budget_Remaining - Budget_Bonus;
if(remaining >= 0)
return 0.f;
if(Budget_Total < 100)
return float(-remaining) / 100.f;
return float(-remaining) / float(Budget_Total);
}
int getMoneyFromType(uint type) {
if(type < MoT_COUNT)
return moneyTypes[type];
return 0;
}
int get_EstNextBudget() const {
int budget = Budget_Total - Maintenance + Budget_Forward;
budget += min(Budget_Remaining - min(PrevBudget - PrevMaintenance, 0), 0);
return budget;
}
int getEstBudgetConsuming(int amount) const {
int budget = Budget_Total - Maintenance + Budget_Forward;
budget += min(Budget_Remaining - amount - min(PrevBudget - PrevMaintenance, 0), 0);
return budget;
}
void addBonusBudget(Empire& emp, int amount) {
amount = floor(double(amount) * emp.SpecialFundsFactor);
Lock lock(budgetMutex);
Budget_Bonus += amount;
Budget_CycleBonus += amount;
Budget_Remaining += amount;
}
int get_BudgetCycleId() {
return Budget_CycleId;
}
uint get_WelfareMode() const {
return welfareMode;
}
void set_WelfareMode(uint mode) {
welfareMode = mode;
}
int consumeBudget(int amount, bool borrow) {
if(amount == 0)
return Budget_CycleId;
Lock lock(budgetMutex);
if(Budget_Remaining >= amount) {
Budget_Remaining -= amount;
Budget_Bonus = max(Budget_Bonus - amount, 0);
return Budget_CycleId;
}
else {
if(!borrow)
return -1;
int borrowAmount = amount;
if(Budget_Remaining > 0)
borrowAmount -= Budget_Remaining;
int borrowCost = ceil(double(borrowAmount) * Borrow_Rate);
if(getEstBudgetConsuming(borrowCost) < borrowCost)
return -1;
Budget_Remaining -= amount;
Budget_Bonus = max(Budget_Bonus - amount, 0);
Budget_Forward -= (borrowCost - borrowAmount);
return Budget_CycleId;
}
}
int lowerBudget(int amount) {
Lock lock(budgetMutex);
if(Budget_Remaining >= amount) {
Budget_Remaining -= amount;
Budget_Bonus = max(Budget_Bonus - amount, 0);
return Budget_CycleId;
}
else {
int borrowAmount = amount;
if(Budget_Remaining > 0)
borrowAmount -= Budget_Remaining;
int borrowCost = ceil(double(borrowAmount) * Borrow_Rate);
Budget_Remaining -= amount;
Budget_Bonus = max(Budget_Bonus - amount, 0);
Budget_Forward -= (borrowCost - borrowAmount);
return Budget_CycleId;
}
}
bool canBorrow(int amount) const {
if(amount == 0)
return true;
amount = ceil(double(amount) * Borrow_Rate);
return getEstBudgetConsuming(amount) >= amount;
}
bool canPay(int amount) const {
if(amount == 0)
return true;
if(amount <= Budget_Remaining)
return true;
return canBorrow(amount - Budget_Remaining);
}
void refundBudget(int amount, int cycleId) {
Lock lock(budgetMutex);
if(cycleId != Budget_CycleId)
return;
int refundedBorrow = min(amount, -Budget_Remaining);
Budget_Remaining += amount;
Budget_Bonus = min(Budget_Bonus + amount, Budget_CycleBonus);
if(refundedBorrow > 0)
Budget_Forward += round(double(refundedBorrow) * (Borrow_Rate - 1.0));
}
void modMaintenance(int amount, uint type = 0) {
Lock lock(budgetMutex);
Maintenance += amount;
if(type < MoT_COUNT)
moneyTypes[type] -= amount;
}
void modTotalBudget(Empire& emp, int amount, uint type = 0) {
Lock lock(budgetMutex);
Budget_Total += amount;
if(type < MoT_COUNT)
moneyTypes[type] += amount;
}
void modForwardBudget(int amount) {
Lock lock(budgetMutex);
Budget_Forward += amount;
}
void modRemainingBudget(int amount) {
Lock lock(budgetMutex);
Budget_Remaining += amount;
}
void resetBudget(Empire& emp) {
if(Budget_CycleId != 0) {
int remaining = Budget_Remaining + storedWelfare - Budget_Bonus;
//New values for each welfare type
int nwf_influence = 0, nwf_energy = 0, nwf_research = 0, nwf_hw_labor = 0, nwf_defense = 0;
if(remaining > 0) {
switch(welfareMode) {
case WM_Influence:
{
double fact = MONEY_PER_INFLUENCE / emp.WelfareEfficiency;
nwf_influence = floor(double(remaining) / fact);
storedWelfare = remaining - (nwf_influence * fact);
} break;
case WM_Energy:
{
double fact = MONEY_PER_ENERGY / emp.WelfareEfficiency;
nwf_energy = floor(double(remaining) / fact);
storedWelfare = remaining - (nwf_energy * fact);
} break;
case WM_Research:
{
double fact = MONEY_PER_RESEARCH / emp.WelfareEfficiency;
nwf_research = floor(double(remaining) / fact);
storedWelfare = remaining - (nwf_research * fact);
} break;
case WM_HW_Labor:
{
double fact = MONEY_PER_HW_LABOR / emp.WelfareEfficiency;
nwf_hw_labor = floor(double(remaining) / fact);
storedWelfare = remaining - (nwf_hw_labor * fact);
} break;
case WM_Defense:
{
double fact = MONEY_PER_DEFENSE / emp.WelfareEfficiency;
nwf_defense = floor(double(remaining) / fact);
storedWelfare = remaining - (nwf_defense * fact);
} break;
default:
storedWelfare = remaining;
break;
}
}
else {
storedWelfare = 0;
}
if(nwf_influence != welfareInfluence) {
emp.modInfluenceIncome(nwf_influence - welfareInfluence);
welfareInfluence = nwf_influence;
}
if(nwf_energy != welfareEnergy) {
emp.modEnergyIncome(double(nwf_energy - welfareEnergy) * TILE_ENERGY_RATE);
welfareEnergy = nwf_energy;
}
if(nwf_research != welfareResearch) {
emp.modResearchRate(double(nwf_research - welfareResearch) * TILE_RESEARCH_RATE);
welfareResearch = nwf_research;
}
if(nwf_defense != welfareDefense) {
emp.modDefenseRate(double(nwf_defense - welfareDefense) * (1.0 / 60.0));
welfareDefense = nwf_defense;
}
if(nwf_hw_labor != welfareHWLabor) {
Object@ home = emp.Homeworld;
if(home is null) {
@home = emp.HomeObj;
if(home !is null && !home.hasConstruction)
@home = null;
}
if(home !is null && home.valid) {
if(home.owner !is emp) {
//In case we lose access to our homeworld, reset the labor being sent
nwf_hw_labor = 0;
welfareMode = WM_Influence;
}
home.modLaborIncome(double(nwf_hw_labor - welfareHWLabor) * TILE_LABOR_RATE);
}
welfareHWLabor = nwf_hw_labor;
}
}
Budget_CycleBonus = Budget_Bonus;
Budget_Remaining = EstNextBudget + Budget_Bonus;
PrevBudget = Budget_Total;
PrevMaintenance = Maintenance;
Budget_Forward = 0;
Budget_Tick = 0;
++Budget_CycleId;
}
void resourceTick(Empire& emp, double time) {
StatRecordDelay -= time;
bool recordStats = StatRecordDelay <= 0;
if(recordStats)
StatRecordDelay += 5.0;
Object@ home = emp.HomeObj;
if(home is null || !home.valid || home.owner !is emp)
@emp.HomeObj = null;
//Handle FTL income rate
{
Lock lock(ftlMutex);
FTL_Stored = clamp(FTL_Stored + time * (FTL_Income - FTL_Use * emp.FTLCostFactor), 0, max(FTL_Capacity, FTL_Stored));
if(FTL_Use > 0) {
double usedFTL = time * min(FTL_Use * emp.FTLCostFactor, FTL_Stored + FTL_Income);
if(usedFTL > 0)
emp.modAttribute(EA_FTLEnergySpent, AC_Add, usedFTL);
}
if(recordStats)
emp.recordStat(stat::FTL, float(FTL_Stored));
}
//Handle Energy income rate
{
Lock lock(energyMutex);
double netEnergy = ((Energy_Income * emp.EnergyGenerationFactor) - Energy_Use);
if(netEnergy > 0)
netEnergy *= emp.EnergyEfficiency;
Energy_Stored = max(Energy_Stored + time * netEnergy, 0.0);
if(recordStats)
emp.recordStat(stat::EnergyIncome, netEnergy);
}
//Handle budget ticks
{
Lock lock(budgetMutex);
if(Budget_Tick >= Budget_Cycle) {
double remainder = Budget_Tick - Budget_Cycle;
resetBudget(emp);
Budget_Tick += remainder;
}
else
Budget_Tick += time;
if(recordStats) {
emp.recordStat(stat::Budget, float(Budget_Total));
emp.recordStat(stat::NetBudget, float(EstNextBudget));
}
}
//Handle extra stats
if(recordStats) {
emp.recordStat(stat::Points, emp.points.value);
emp.recordStat(stat::Military, float(sqr(emp.TotalMilitary) * 0.001));
}
}
//Networking
void writeResources(Message& msg) {
msg << float(Population);
msg << float(FTL_Capacity);
msg << float(FTL_Stored);
msg << float(FTL_Income);
msg << float(FTL_Use);
msg << float(Energy_Stored);
msg << float(Energy_Income);
msg << float(Energy_Use);
msg << float(Energy_Allocated);
msg << Budget_Total;
msg << Maintenance;
msg << PrevMaintenance;
msg << PrevBudget;
msg << Budget_Remaining;
msg << Budget_Forward;
msg << Budget_Bonus;
msg << Budget_CycleId;
msg << float(Budget_Cycle);
msg << float(Budget_Tick);
msg << float(Borrow_Rate);
for(uint i = 0; i < MoT_COUNT; ++i)
msg.writeSignedSmall(moneyTypes[i]);
msg.writeLimited(welfareMode, WM_COUNT-1);
}
};