config organization

This commit is contained in:
Rudis Muiznieks 2021-09-05 20:43:11 -05:00
parent d0e58996a1
commit ce3ae26b4b
15 changed files with 108 additions and 83 deletions

View File

@ -27,49 +27,55 @@ class GameConfig {
public relNoneShare = 0.16; public relNoneShare = 0.16;
// general configs // general configs
public cfgPassiveMax = 100; public cfgInitialMax: ResourceNumber = {
cryptoCurrency: 1000,
megaChurches: 2,
money: 500000,
playerOrg: 5,
tents: 5,
};
public cfgInitialCost: ResourceNumber = {
buildingPermit: 250000,
churches: 150000,
compounds: 15000,
cryptoCurrency: 100,
houses: 75000,
megaChurches: 750000,
tents: 250,
};
public cfgCostMultiplier: ResourceNumber = {
churches: 1.01,
compounds: 1.5,
cryptoCurrency: 1.1,
houses: 1.01,
megaChurches: 1.01,
tents: 1.05,
};
public cfgSalary: ResourceNumber = {
pastors: 7.5,
};
public cfgCapacity: { [key in ResourceKey]?: ResourceNumber } = {
churches: { pastors: 2 },
compounds: { churches: 1, houses: 2, money: 500000, tents: 10 },
houses: { playerOrg: 10 },
megaChurches: { pastors: 5 },
tents: { playerOrg: 2 },
};
public cfgCredibilityFollowerLossRatio = 0.04; public cfgCredibilityFollowerLossRatio = 0.04;
public cfgCredibilityFollowerLossTime = 10000; public cfgCredibilityFollowerLossTime = 10000;
public cfgCredibilityRestoreRate = 0.25; public cfgCredibilityRestoreRate = 0.25;
public cfgCryptoReturnAmount = 1;
public cfgFollowerGainLossLogTimer = 10000;
public cfgPassiveMax = 100;
public cfgPastorRecruitRate = 0.01; public cfgPastorRecruitRate = 0.01;
public cfgPastorTitheCollectionFollowerMax = 100; public cfgPastorTitheCollectionFollowerMax = 100;
public cfgPastorSalary = 7.5;
public cfgFollowerGainLossLogTimer = 10000;
public cfgFollowerStartingMax = 5;
public cfgTimeBetweenTithes = 30000; public cfgTimeBetweenTithes = 30000;
public cfgTitheAmount = 10; public cfgTitheAmount = 10;
public cfgCryptoReturnAmount = 1;
public cfgMoneyStartingMax = 500000;
public cfgBuildingPermitCost = 250000;
public cfgChurchCostMultiplier = 1.01;
public cfgChurchPastorCapacity = 2;
public cfgChurchStartingCost = 150000;
public cfgCompoundChurchCapacity = 1;
public cfgCompoundCostMultiplier = 1.5;
public cfgCompoundHouseCapacity = 2;
public cfgCompoundMoneyCapacity = 500000;
public cfgCompoundStartingCost = 15000;
public cfgCompoundTentCapacity = 10;
public cfgCryptoCostMultiplier = 1.1;
public cfgCryptoStartingCost = 100;
public cfgCryptoStartingMax = 1000;
public cfgHouseCostMultiplier = 1.01;
public cfgHouseFollowerCapacity = 10;
public cfgHouseStartingCost = 75000;
public cfgMegaChurchCostMultiplier = 1.01;
public cfgMegaChurchPastorCapacity = 5;
public cfgMegaChurchStartingCost = 7500000;
public cfgMegaChurchStartingMax = 2;
public cfgTentCostMultiplier = 1.05;
public cfgTentFollowerCapacity = 2;
public cfgTentStartingCost = 250;
public cfgTentStartingMax = 5;
public generateState (): GameState { public generateState (): GameState {
const state = new GameState(this); const state = new GameState(this);

View File

@ -81,7 +81,7 @@ class GameState {
} }
} }
public deductCost (cost: { [key in ResourceKey]?: number } | null): boolean { public deductCost (cost: ResourceNumber | null): boolean {
if (cost === null) return true; if (cost === null) return true;
if (!this.isPurchasable(cost)) return false; if (!this.isPurchasable(cost)) return false;
for (const key in cost) { for (const key in cost) {
@ -94,8 +94,7 @@ class GameState {
return true; return true;
} }
public isPurchasable ( public isPurchasable (cost?: ResourceNumber): boolean {
cost?: { [key in ResourceKey]?: number }): boolean {
if (cost === undefined) return true; if (cost === undefined) return true;
for (const key in cost) { for (const key in cost) {
const rkey = <ResourceKey>key; const rkey = <ResourceKey>key;

View File

@ -4,7 +4,7 @@ class BuildingPermit extends Research {
constructor (config: GameConfig) { constructor (config: GameConfig) {
super('Building Permit', super('Building Permit',
'Unlocks several new buildings you can build outside of your compounds.'); 'Unlocks several new buildings you can build outside of your compounds.');
this.cost.money = config.cfgBuildingPermitCost; this.cost.money = config.cfgInitialMax.buildingPermit;
} }
public isUnlocked (state: GameState): boolean { public isUnlocked (state: GameState): boolean {

View File

@ -3,14 +3,14 @@
class Church extends Infrastructure { class Church extends Infrastructure {
constructor (config: GameConfig) { constructor (config: GameConfig) {
super('Churches', super('Churches',
`Preaching grounds for ${config.formatNumber(config.cfgChurchPastorCapacity)} pastors.`); `Preaching grounds for ${config.formatNumber(config.cfgCapacity.churches?.pastors ?? 0)} pastors.`);
this.cost.money = config.cfgChurchStartingCost; this.cost.money = config.cfgInitialCost.churches;
this._costMultiplier.money = config.cfgChurchCostMultiplier; this._costMultiplier.money = config.cfgCostMultiplier.churches;
} }
public max: (state: GameState) => number = (state) => public max: (state: GameState) => number = (state) =>
(state.resource.compounds?.value ?? 0) (state.resource.compounds?.value ?? 0)
* state.config.cfgCompoundChurchCapacity; * (state.config.cfgCapacity.compounds?.churches ?? 0);
public isUnlocked (state: GameState): boolean { public isUnlocked (state: GameState): boolean {
if (this._isUnlocked) return true; if (this._isUnlocked) return true;

View File

@ -4,14 +4,15 @@ class Compound extends Infrastructure {
constructor (config: GameConfig) { constructor (config: GameConfig) {
super('Compounds', super('Compounds',
'Provides space for tents, houses, and churches and a place to hide more money.'); 'Provides space for tents, houses, and churches and a place to hide more money.');
this.cost.money = config.cfgCompoundStartingCost; this.cost.money = config.cfgInitialCost.compounds;
this._costMultiplier.money = config.cfgCompoundCostMultiplier; this._costMultiplier.money = config.cfgCostMultiplier.compounds;
} }
public isUnlocked (state: GameState): boolean { public isUnlocked (state: GameState): boolean {
if (this._isUnlocked) return true; if (this._isUnlocked) return true;
const tents = state.resource.tents; const tents = state.resource.tents;
if (tents !== undefined && tents.value >= state.config.cfgTentStartingMax) { if (tents !== undefined
&& tents.value >= (state.config.cfgInitialMax.tents ?? 0)) {
this._isUnlocked = true; this._isUnlocked = true;
} }
return this._isUnlocked; return this._isUnlocked;

View File

@ -4,11 +4,11 @@ class CryptoCurrency extends Purchasable {
constructor (config: GameConfig) { constructor (config: GameConfig) {
super('Faithcoin', super('Faithcoin',
"A crypto coin that can't be spent directly, but provides a steady stream of passive income."); "A crypto coin that can't be spent directly, but provides a steady stream of passive income.");
this.cost.money = config.cfgCryptoStartingCost; this.cost.money = config.cfgInitialCost.cryptoCurrency;
this._costMultiplier.money = config.cfgCryptoCostMultiplier; this._costMultiplier.money = config.cfgCostMultiplier.cryptoCurrency;
this.valueInWholeNumbers = false; this.valueInWholeNumbers = false;
} }
public max: (state: GameState) => number = (state) => public max: (state: GameState) => number = (state) =>
state.config.cfgCryptoStartingMax; state.config.cfgInitialMax.cryptoCurrency ?? 0;
} }

View File

@ -3,14 +3,14 @@
class House extends Infrastructure { class House extends Infrastructure {
constructor (config: GameConfig) { constructor (config: GameConfig) {
super('Houses', super('Houses',
`Provides room to house ${config.formatNumber(config.cfgHouseFollowerCapacity)} followers.`); `Provides room to house ${config.formatNumber(config.cfgCapacity.houses?.playerOrg ?? 0)} followers.`);
this.cost.money = config.cfgHouseStartingCost; this.cost.money = config.cfgInitialCost.houses;
this._costMultiplier.money = config.cfgHouseCostMultiplier; this._costMultiplier.money = config.cfgCostMultiplier.houses;
} }
public max: (state: GameState) => number = (state) => public max: (state: GameState) => number = (state) =>
(state.resource.compounds?.value ?? 0) (state.resource.compounds?.value ?? 0)
* state.config.cfgCompoundHouseCapacity; * (state.config.cfgCapacity.compounds?.houses ?? 0);
public isUnlocked (state: GameState): boolean { public isUnlocked (state: GameState): boolean {
if (this._isUnlocked) return true; if (this._isUnlocked) return true;

View File

@ -29,6 +29,8 @@ enum ResourceKey {
credibility = 'credibility', credibility = 'credibility',
} }
type ResourceNumber = { [key in ResourceKey]?: number };
interface IResource { interface IResource {
readonly resourceType: ResourceType; readonly resourceType: ResourceType;
readonly name: string; readonly name: string;
@ -36,7 +38,7 @@ interface IResource {
readonly valueInWholeNumbers: boolean; readonly valueInWholeNumbers: boolean;
readonly value: number; readonly value: number;
readonly cost?: { [key in ResourceKey]?: number }; readonly cost?: ResourceNumber;
readonly clickText?: string; readonly clickText?: string;
readonly clickDescription?: string; readonly clickDescription?: string;

View File

@ -6,7 +6,7 @@ abstract class Job implements IResource {
public readonly clickText = 'Hire'; public readonly clickText = 'Hire';
public readonly clickDescription = 'Promote one of your followers.'; public readonly clickDescription = 'Promote one of your followers.';
public value = 0; public value = 0;
public readonly cost: { [key in ResourceKey]?: number } = { }; public readonly cost: ResourceNumber = { };
public max?: (state: GameState) => number = undefined; public max?: (state: GameState) => number = undefined;
public inc?: (state: GameState) => number = undefined; public inc?: (state: GameState) => number = undefined;
@ -38,13 +38,19 @@ abstract class Job implements IResource {
public addValue (amount: number): void { public addValue (amount: number): void {
this.value += amount; this.value += amount;
if (this.value < 0) this.value = 0;
} }
public isUnlocked (_state: GameState): boolean { public isUnlocked (_state: GameState): boolean {
return this._isUnlocked; return this._isUnlocked;
} }
public advanceAction (_time: number, _state: GameState): void { public advanceAction (_time: number, state: GameState): void {
// if we're out of followers then the jobs also vacate
const avail = this._availableJobs(state);
if (avail < 0 && this.value > 0) {
this.addValue(avail);
}
return; return;
} }
@ -58,9 +64,20 @@ abstract class Job implements IResource {
? tot + res.value ? tot + res.value
: tot; : tot;
}, 0); }, 0);
let max = followers - hired; return followers - hired;
if (max < 0) max = 0; }
return max;
protected _totalPayroll (state: GameState): number {
// number of followers minus the number of filled jobs
const followers = state.resource.playerOrg?.value ?? 0;
const hired = state.resources.reduce(
(tot: number, rkey: ResourceKey): number => {
const res = state.resource[rkey];
return res?.resourceType === ResourceType.job
? tot + res.value
: tot;
}, 0);
return followers - hired;
} }
protected _hireLog (amount: number, _state: GameState): string { protected _hireLog (amount: number, _state: GameState): string {

View File

@ -3,13 +3,13 @@
class MegaChurch extends Infrastructure { class MegaChurch extends Infrastructure {
constructor (config: GameConfig) { constructor (config: GameConfig) {
super('MegaChurches', super('MegaChurches',
`Room for ${config.formatNumber(config.cfgMegaChurchPastorCapacity)} pastors`); `Room for ${config.formatNumber(config.cfgCapacity.megaChurches?.pastors ?? 0)} pastors`);
this.cost.money = config.cfgMegaChurchStartingCost; this.cost.money = config.cfgInitialCost.megaChurches;
this._costMultiplier.money = config.cfgMegaChurchCostMultiplier; this._costMultiplier.money = config.cfgCostMultiplier.megaChurches;
} }
public max: (state: GameState) => number = (state) => public max: (state: GameState) => number = (state) =>
state.config.cfgMegaChurchStartingMax; state.config.cfgInitialMax.megaChurches ?? 0;
public isUnlocked (state: GameState): boolean { public isUnlocked (state: GameState): boolean {
if (this._isUnlocked) return true; if (this._isUnlocked) return true;

View File

@ -16,9 +16,9 @@ class Money extends Purchasable {
} }
public max: (state: GameState) => number = (state: GameState) => { public max: (state: GameState) => number = (state: GameState) => {
let max = state.config.cfgMoneyStartingMax; let max = state.config.cfgInitialMax.money ?? 0;
max += (state.resource.compounds?.value ?? 0) max += (state.resource.compounds?.value ?? 0)
* state.config.cfgCompoundMoneyCapacity; * (state.config.cfgCapacity.compounds?.money ?? 0);
return max; return max;
}; };
@ -31,7 +31,7 @@ class Money extends Purchasable {
// salaries // salaries
inc -= (state.resource.pastors?.value ?? 0) inc -= (state.resource.pastors?.value ?? 0)
* state.config.cfgPastorSalary; * (state.config.cfgSalary.pastors ?? 0);
return inc; return inc;
}; };

View File

@ -8,12 +8,11 @@ class Pastor extends Job {
'Collect tithings for you and recruit new members from other faiths automatically.'); 'Collect tithings for you and recruit new members from other faiths automatically.');
} }
public max: (state: GameState) => number = (state) => { public max: (state: GameState) => number = (state) => {
let max = (state.resource.churches?.value ?? 0) let max = (state.resource.churches?.value ?? 0)
* state.config.cfgChurchPastorCapacity; * (state.config.cfgCapacity.churches?.pastors ?? 0);
max += (state.resource.megaChurches?.value ?? 0) max += (state.resource.megaChurches?.value ?? 0)
* state.config.cfgMegaChurchPastorCapacity; * (state.config.cfgCapacity.megaChurches?.pastors ?? 0);
return max; return max;
}; };
@ -24,12 +23,13 @@ class Pastor extends Job {
} }
public advanceAction (time: number, state: GameState): void { public advanceAction (time: number, state: GameState): void {
super.advanceAction(time, state);
this._timeSinceLastTithe += time; this._timeSinceLastTithe += time;
if (this._timeSinceLastTithe >= state.config.cfgTimeBetweenTithes) { if (this._timeSinceLastTithe >= state.config.cfgTimeBetweenTithes) {
const money = state.resource.money; const money = state.resource.money;
const plorg = state.resource.playerOrg; const plorg = state.resource.playerOrg;
let tithed = this.value let tithed = Math.floor(this.value
* state.config.cfgPastorTitheCollectionFollowerMax; * state.config.cfgPastorTitheCollectionFollowerMax);
if (Math.floor(plorg?.value ?? 0) < tithed) if (Math.floor(plorg?.value ?? 0) < tithed)
tithed = Math.floor(plorg?.value ?? 0); tithed = Math.floor(plorg?.value ?? 0);
let collected = tithed * state.config.cfgTitheAmount; let collected = tithed * state.config.cfgTitheAmount;

View File

@ -11,15 +11,15 @@ class PlayerOrg implements IResource {
private _timeSinceLastLost = 0; private _timeSinceLastLost = 0;
private _lastRecruitmentLog = 0; private _lastRecruitmentLog = 0;
private _followerSources: { [key in ResourceKey]?: number } = { }; private _followerSources: ResourceNumber = { };
private _followerDests: { [key in ResourceKey]?: number } = { }; private _followerDests: ResourceNumber = { };
public max (state: GameState): number { public max (state: GameState): number {
let max = state.config.cfgFollowerStartingMax; let max = state.config.cfgInitialMax.playerOrg ?? 0;
max += (state.resource.tents?.value ?? 0) max += (state.resource.tents?.value ?? 0)
* state.config.cfgTentFollowerCapacity; * (state.config.cfgCapacity.tents?.playerOrg ?? 0);
max += (state.resource.houses?.value ?? 0) max += (state.resource.houses?.value ?? 0)
* state.config.cfgHouseFollowerCapacity; * (state.config.cfgCapacity.houses?.playerOrg ?? 0);
return max; return max;
} }

View File

@ -6,12 +6,12 @@ abstract class Purchasable implements IResource {
public clickText = 'Purchase'; public clickText = 'Purchase';
public clickDescription = 'Purchase'; public clickDescription = 'Purchase';
public value = 0; public value = 0;
public readonly cost: { [key in ResourceKey]?: number } = { }; public readonly cost: ResourceNumber = { };
public inc?: (state: GameState) => number = undefined; public inc?: (state: GameState) => number = undefined;
public max?: (_state: GameState) => number = undefined; public max?: (_state: GameState) => number = undefined;
protected _costMultiplier: { [key in ResourceKey]?: number } = { }; protected _costMultiplier: ResourceNumber = { };
protected _isUnlocked = false; protected _isUnlocked = false;
constructor ( constructor (

View File

@ -3,16 +3,16 @@
class Tent extends Infrastructure { class Tent extends Infrastructure {
constructor (config: GameConfig) { constructor (config: GameConfig) {
super('Tents', super('Tents',
`Provides room to house ${config.formatNumber(config.cfgTentFollowerCapacity)} followers.`); `Provides room to house ${config.formatNumber(config.cfgCapacity.tents?.playerOrg ?? 0)} followers.`);
this.cost.money = config.cfgTentStartingCost; this.cost.money = config.cfgInitialCost.tents;
this._costMultiplier.money = config.cfgTentCostMultiplier; this._costMultiplier.money = config.cfgCostMultiplier.tents;
} }
public max: (state: GameState) => number = (state) => { public max: (state: GameState) => number = (state) => {
// ten extra tents per compound // ten extra tents per compound
let max = state.config.cfgTentStartingMax; let max = state.config.cfgInitialMax.tents ?? 0;
max += (state.resource.compounds?.value ?? 0) max += (state.resource.compounds?.value ?? 0)
* state.config.cfgCompoundTentCapacity; * (state.config.cfgCapacity.compounds?.tents ?? 0);
return max; return max;
}; };
} }