replaced hard-coded values with configs
This commit is contained in:
parent
caf5152551
commit
3f57d6ce91
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
class GameConfig {
|
class GameConfig {
|
||||||
public worldPopulation = 790000000;
|
public worldPopulation = 790000000;
|
||||||
|
public numberFormatDigits = 1;
|
||||||
|
|
||||||
// religion configs
|
// religion configs
|
||||||
public relChristianitySharer = 0.325;
|
public relChristianitySharer = 0.325;
|
||||||
|
@ -25,73 +26,128 @@ class GameConfig {
|
||||||
public relOtherShare = 0.02;
|
public relOtherShare = 0.02;
|
||||||
public relNoneShare = 0.16;
|
public relNoneShare = 0.16;
|
||||||
|
|
||||||
public cfgStartingPlayerMax = 5;
|
// general configs
|
||||||
public cfgStartingMoneyMax = 500000;
|
public cfgPassiveMax = 100;
|
||||||
public cfgStartingTentMax = 5;
|
|
||||||
public cfgStartingCryptoMax = 1000;
|
|
||||||
public cfgStartingMegaChurchMax = 2;
|
|
||||||
|
|
||||||
public cfgTitheAmount = 10;
|
public cfgCredibilityFollowerLossRatio = 0.04;
|
||||||
public cfgTimeBetweenTithes = 30000;
|
public cfgCredibilityFollowerLossTime = 10000;
|
||||||
public cfgCryptoReturnAmount = 1;
|
|
||||||
public cfgCredibilityRestoreRate = 0.25;
|
public cfgCredibilityRestoreRate = 0.25;
|
||||||
|
|
||||||
|
public cfgFollowerGainLossLogTimer = 10000;
|
||||||
|
public cfgFollowerStartingMax = 5;
|
||||||
public cfgPastorRecruitRate = 0.01;
|
public cfgPastorRecruitRate = 0.01;
|
||||||
|
|
||||||
|
public cfgTimeBetweenTithes = 30000;
|
||||||
|
public cfgTitheAmount = 10;
|
||||||
|
public cfgCryptoReturnAmount = 1;
|
||||||
|
public cfgMoneyStartingMax = 500000;
|
||||||
|
public cfgPastorTitheCollectionFollowerMax = 100;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
// create player organization
|
// create player organization
|
||||||
state.addResource('plorg', new PlayerOrg());
|
state.addResource(ResourceKey.playerOrg, new PlayerOrg());
|
||||||
|
|
||||||
// create world religions
|
// create world religions
|
||||||
state.addResource('xtian', new Religion(
|
state.addResource(ResourceKey.christianity, new Religion(
|
||||||
'Christianity', 'God, Jesus, Bible, churches.',
|
'Christianity', 'God, Jesus, Bible, churches.',
|
||||||
this.relChristianitySharer * this.worldPopulation));
|
this.relChristianitySharer * this.worldPopulation));
|
||||||
|
|
||||||
state.addResource('islam', new Religion(
|
state.addResource(ResourceKey.islam, new Religion(
|
||||||
'Islam', 'God, Muhammad, Quran, mosques.',
|
'Islam', 'God, Muhammad, Quran, mosques.',
|
||||||
this.relIslamShare * this.worldPopulation));
|
this.relIslamShare * this.worldPopulation));
|
||||||
|
|
||||||
state.addResource('hindu', new Religion(
|
state.addResource(ResourceKey.hinduism, new Religion(
|
||||||
'Hinduism', 'Dogma-free spiritualism.',
|
'Hinduism', 'Dogma-free spiritualism.',
|
||||||
this.relHinduismShare * this.worldPopulation));
|
this.relHinduismShare * this.worldPopulation));
|
||||||
|
|
||||||
state.addResource('buddh', new Religion(
|
state.addResource(ResourceKey.buddhism, new Religion(
|
||||||
'Buddhism', 'The minimization of suffering.',
|
'Buddhism', 'The minimization of suffering.',
|
||||||
this.relBuddhismShare * this.worldPopulation));
|
this.relBuddhismShare * this.worldPopulation));
|
||||||
|
|
||||||
state.addResource('sikhi', new Religion(
|
state.addResource(ResourceKey.sikhism, new Religion(
|
||||||
'Sikhism', 'Meditation and ten Gurus',
|
'Sikhism', 'Meditation and ten Gurus',
|
||||||
this.relSikhismShare * this.worldPopulation));
|
this.relSikhismShare * this.worldPopulation));
|
||||||
|
|
||||||
state.addResource('judah', new Religion(
|
state.addResource(ResourceKey.judaism, new Religion(
|
||||||
'Judaism', 'God, Abraham, Torah, synagogues.',
|
'Judaism', 'God, Abraham, Torah, synagogues.',
|
||||||
this.relJudaismShare * this.worldPopulation));
|
this.relJudaismShare * this.worldPopulation));
|
||||||
|
|
||||||
state.addResource('other', new Religion(
|
state.addResource(ResourceKey.other, new Religion(
|
||||||
'Other', 'A variety of belief systems.',
|
'Other', 'A variety of belief systems.',
|
||||||
this.relOtherShare * this.worldPopulation));
|
this.relOtherShare * this.worldPopulation));
|
||||||
|
|
||||||
state.addResource('agnos', new Religion(
|
state.addResource(ResourceKey.atheism, new Religion(
|
||||||
'Non-Religious', 'Atheists and agnostics.',
|
'Non-Religious', 'Atheists and agnostics.',
|
||||||
this.relNoneShare * this.worldPopulation));
|
this.relNoneShare * this.worldPopulation));
|
||||||
|
|
||||||
// add jobs
|
// add jobs
|
||||||
state.addResource('pstor', new Pastor());
|
state.addResource(ResourceKey.pastors, new Pastor());
|
||||||
|
|
||||||
// add resources
|
// add resources
|
||||||
state.addResource('money', new Money(3.50));
|
state.addResource(ResourceKey.money, new Money(3.50));
|
||||||
state.addResource('crpto', new CryptoCurrency());
|
state.addResource(ResourceKey.faithCoin, new CryptoCurrency(this));
|
||||||
state.addResource('tents', new Tent());
|
state.addResource(ResourceKey.tents, new Tent(this));
|
||||||
state.addResource('house', new House());
|
state.addResource(ResourceKey.houses, new House(this));
|
||||||
state.addResource('chrch', new Church());
|
state.addResource(ResourceKey.churches, new Church(this));
|
||||||
state.addResource('cmpnd', new Compound());
|
state.addResource(ResourceKey.compounds, new Compound(this));
|
||||||
state.addResource('blpmt', new BuildingPermit());
|
state.addResource(ResourceKey.megaChurches, new MegaChurch(this));
|
||||||
state.addResource('mchch', new MegaChurch());
|
|
||||||
|
// add research
|
||||||
|
state.addResource(ResourceKey.buildingPermit, new BuildingPermit(this));
|
||||||
|
|
||||||
// add passive resources
|
// add passive resources
|
||||||
state.addResource('creds', new Credibility());
|
state.addResource(ResourceKey.credibility, new Credibility(this));
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public formatNumber (num: number): string {
|
||||||
|
type UnitLookup = { value: number, symbol: string };
|
||||||
|
const lookup: UnitLookup[] = [
|
||||||
|
{ value: 1, symbol: '' },
|
||||||
|
{ value: 1e3, symbol: 'K' },
|
||||||
|
{ value: 1e6, symbol: 'M' },
|
||||||
|
{ value: 1e9, symbol: 'G' },
|
||||||
|
{ value: 1e12, symbol: 'T' },
|
||||||
|
{ value: 1e15, symbol: 'P' },
|
||||||
|
{ value: 1e18, symbol: 'E' },
|
||||||
|
];
|
||||||
|
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||||
|
let item: UnitLookup | undefined;
|
||||||
|
for (item of lookup.slice().reverse()) {
|
||||||
|
if (num >= item.value) break;
|
||||||
|
}
|
||||||
|
return item !== undefined
|
||||||
|
? (num / item.value).toFixed(
|
||||||
|
this.numberFormatDigits).replace(rx, '$1') + item.symbol
|
||||||
|
: num.toFixed(this.numberFormatDigits).replace(rx, '$1');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ class GameState {
|
||||||
|
|
||||||
public onResourceClick: Array<() => void> = [];
|
public onResourceClick: Array<() => void> = [];
|
||||||
public logger: ILogger | null = null;
|
public logger: ILogger | null = null;
|
||||||
public numberFormatDigits = 1;
|
|
||||||
|
|
||||||
public now = 0;
|
public now = 0;
|
||||||
|
|
||||||
|
@ -13,15 +12,15 @@ class GameState {
|
||||||
private _timeSinceSave = 0;
|
private _timeSinceSave = 0;
|
||||||
private readonly _timeBetweenSaves = 10000;
|
private readonly _timeBetweenSaves = 10000;
|
||||||
|
|
||||||
private _resources: { [key: string]: IResource } = { };
|
private _resources: { [key in ResourceKey]?: IResource } = { };
|
||||||
private readonly _resourceKeys: string[] = [];
|
private readonly _resourceKeys: ResourceKey[] = [];
|
||||||
|
|
||||||
|
|
||||||
constructor (config: GameConfig) {
|
constructor (config: GameConfig) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addResource (key: string, resource: IResource): void {
|
public addResource (key: ResourceKey, resource: IResource): void {
|
||||||
this._resourceKeys.push(key);
|
this._resourceKeys.push(key);
|
||||||
this._resources[key] = resource;
|
this._resources[key] = resource;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +37,7 @@ class GameState {
|
||||||
// advance each resource
|
// advance each resource
|
||||||
for (const rkey of this._resourceKeys) {
|
for (const rkey of this._resourceKeys) {
|
||||||
const resource = this._resources[rkey];
|
const resource = this._resources[rkey];
|
||||||
if (this._resources[rkey].isUnlocked(this)) {
|
if (resource?.isUnlocked(this) === true) {
|
||||||
if (resource.advanceAction !== null)
|
if (resource.advanceAction !== null)
|
||||||
resource.advanceAction(time, this);
|
resource.advanceAction(time, this);
|
||||||
}
|
}
|
||||||
|
@ -47,34 +46,34 @@ class GameState {
|
||||||
// perform auto increments
|
// perform auto increments
|
||||||
for (const rkey of this._resourceKeys) {
|
for (const rkey of this._resourceKeys) {
|
||||||
const resource = this._resources[rkey];
|
const resource = this._resources[rkey];
|
||||||
if (!resource.isUnlocked(this)) continue;
|
if (resource === undefined || !resource.isUnlocked(this)) continue;
|
||||||
|
|
||||||
if (resource.inc !== null && (resource.max === null
|
if (resource.inc !== null && (resource.max === null
|
||||||
|| this._resources[rkey].value < resource.max(this))) {
|
|| resource.value < resource.max(this))) {
|
||||||
this._resources[rkey].addValue(resource.inc(this) * time / 1000, this);
|
resource.addValue(resource.inc(this) * time / 1000, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.max !== null && resource.value > resource.max(this)) {
|
if (resource.max !== null && resource.value > resource.max(this)) {
|
||||||
this._resources[rkey].addValue(
|
resource.addValue((resource.value - resource.max(this)) * -1, this);
|
||||||
(resource.value - resource.max(this)) * -1, this);
|
|
||||||
}
|
}
|
||||||
if (resource.value < 0) {
|
if (resource.value < 0) {
|
||||||
this._resources[rkey].addValue(resource.value * -1, this);
|
resource.addValue(resource.value * -1, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getResources (): string[] {
|
public getResources (): ResourceKey[] {
|
||||||
return this._resourceKeys;
|
return this._resourceKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getResource (key: string): IResource {
|
public getResource (key: ResourceKey): IResource | null {
|
||||||
return this._resources[key];
|
const resource = this._resources[key];
|
||||||
|
return resource !== undefined ? resource : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public performClick (resourceKey: string): void {
|
public performClick (resourceKey: ResourceKey): void {
|
||||||
const resource = this._resources[resourceKey];
|
const resource = this._resources[resourceKey];
|
||||||
if (!resource.isUnlocked(this)) return;
|
if (resource === undefined || !resource.isUnlocked(this)) return;
|
||||||
|
|
||||||
if (resource.clickAction !== null) {
|
if (resource.clickAction !== null) {
|
||||||
resource.clickAction(this);
|
resource.clickAction(this);
|
||||||
|
@ -84,47 +83,31 @@ class GameState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public deductCost (cost: { [rkey: string]: number } | null): boolean {
|
public deductCost (cost: { [key in ResourceKey]?: number } | 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 rkey of Object.keys(cost)) {
|
for (const key in cost) {
|
||||||
this._resources[rkey].addValue(cost[rkey] * -1, this);
|
const rkey = <ResourceKey>key;
|
||||||
|
const resource = this._resources[rkey];
|
||||||
|
const resCost = cost[rkey];
|
||||||
|
if (resource === undefined || resCost === undefined) continue;
|
||||||
|
resource.addValue(resCost * -1, this);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPurchasable (cost: { [rkey: string]: number } | null): boolean {
|
public isPurchasable (
|
||||||
|
cost: { [key in ResourceKey]?: number } | null): boolean {
|
||||||
if (cost === null) return true;
|
if (cost === null) return true;
|
||||||
for (const rkey of Object.keys(cost)) {
|
for (const key in cost) {
|
||||||
if (this._resources[rkey].value < cost[rkey]) {
|
const rkey = <ResourceKey>key;
|
||||||
|
if ((this._resources[rkey]?.value ?? 0) < (cost[rkey] ?? 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public formatNumber (num: number): string {
|
|
||||||
type UnitLookup = { value: number, symbol: string };
|
|
||||||
const lookup: UnitLookup[] = [
|
|
||||||
{ value: 1, symbol: '' },
|
|
||||||
{ value: 1e3, symbol: 'K' },
|
|
||||||
{ value: 1e6, symbol: 'M' },
|
|
||||||
{ value: 1e9, symbol: 'G' },
|
|
||||||
{ value: 1e12, symbol: 'T' },
|
|
||||||
{ value: 1e15, symbol: 'P' },
|
|
||||||
{ value: 1e18, symbol: 'E' },
|
|
||||||
];
|
|
||||||
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
|
||||||
let item: UnitLookup | undefined;
|
|
||||||
for (item of lookup.slice().reverse()) {
|
|
||||||
if (num >= item.value) break;
|
|
||||||
}
|
|
||||||
return item !== undefined
|
|
||||||
? (num / item.value).toFixed(
|
|
||||||
this.numberFormatDigits).replace(rx, '$1') + item.symbol
|
|
||||||
: num.toFixed(this.numberFormatDigits).replace(rx, '$1');
|
|
||||||
}
|
|
||||||
|
|
||||||
public log (text: string): void {
|
public log (text: string): void {
|
||||||
if (this.logger !== null) {
|
if (this.logger !== null) {
|
||||||
this.logger.msg(text);
|
this.logger.msg(text);
|
||||||
|
@ -137,10 +120,11 @@ class GameState {
|
||||||
maj: this._versionMaj,
|
maj: this._versionMaj,
|
||||||
min: this._versionMin,
|
min: this._versionMin,
|
||||||
};
|
};
|
||||||
for (const rkey of this._resourceKeys) {
|
for (const key in this._resources) {
|
||||||
|
const rkey = <ResourceKey>key;
|
||||||
saveObj[rkey] = {
|
saveObj[rkey] = {
|
||||||
value: this._resources[rkey].value,
|
value: this._resources[rkey]?.value ?? 0,
|
||||||
cost: this._resources[rkey].cost,
|
cost: this._resources[rkey]?.cost ?? null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const saveStr: string = btoa(JSON.stringify(saveObj));
|
const saveStr: string = btoa(JSON.stringify(saveObj));
|
||||||
|
@ -153,11 +137,12 @@ class GameState {
|
||||||
try {
|
try {
|
||||||
const saveObj: SaveData = <SaveData>JSON.parse(atob(saveStr));
|
const saveObj: SaveData = <SaveData>JSON.parse(atob(saveStr));
|
||||||
if (this._versionMaj === saveObj.version?.maj) {
|
if (this._versionMaj === saveObj.version?.maj) {
|
||||||
for (const rkey of this._resourceKeys) {
|
for (const key in this._resources) {
|
||||||
|
const rkey = <ResourceKey>key;
|
||||||
const saveRes = <{
|
const saveRes = <{
|
||||||
value: number;
|
value: number;
|
||||||
cost: { [key: string]: number } | null;
|
cost: { [key: string]: number } | null;
|
||||||
} | undefined> saveObj[rkey];
|
} | undefined> saveObj[key];
|
||||||
if (saveRes !== undefined) {
|
if (saveRes !== undefined) {
|
||||||
// @ts-expect-error writing read-only value from save data
|
// @ts-expect-error writing read-only value from save data
|
||||||
this._resources[rkey].value = saveRes.value;
|
this._resources[rkey].value = saveRes.value;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
/// <reference path="./Research.ts" />
|
/// <reference path="./Research.ts" />
|
||||||
|
|
||||||
class BuildingPermit extends Research {
|
class BuildingPermit extends Research {
|
||||||
constructor () {
|
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 = 250000;
|
this.cost.money = config.cfgBuildingPermitCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
const compounds = state.getResource('cmpnd');
|
const compounds = state.getResource(ResourceKey.compounds);
|
||||||
if (compounds.value > 0) {
|
if (compounds !== null && compounds.value > 0) {
|
||||||
this._isUnlocked = true;
|
this._isUnlocked = true;
|
||||||
}
|
}
|
||||||
return this._isUnlocked;
|
return this._isUnlocked;
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/// <reference path="./Infrastructure.ts" />
|
/// <reference path="./Infrastructure.ts" />
|
||||||
|
|
||||||
class Church extends Infrastructure {
|
class Church extends Infrastructure {
|
||||||
constructor () {
|
constructor (config: GameConfig) {
|
||||||
super('Churches',
|
super('Churches',
|
||||||
'Preaching grounds for 2 pastors.');
|
`Preaching grounds for ${config.formatNumber(config.cfgChurchPastorCapacity)} pastors.`);
|
||||||
this.cost.money = 150000;
|
this.cost.money = config.cfgChurchStartingCost;
|
||||||
this._costMultiplier.money = 1.01;
|
this._costMultiplier.money = config.cfgChurchCostMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public max: (state: GameState) => number = (state) =>
|
public max: (state: GameState) => number = (state) =>
|
||||||
state.getResource('cmpnd').value;
|
state.getResource(ResourceKey.compounds)?.value ?? 0;
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
const compounds = state.getResource('cmpnd');
|
const compounds = state.getResource(ResourceKey.compounds);
|
||||||
if (compounds.value > 0) {
|
if (compounds != null && compounds.value > 0) {
|
||||||
this._isUnlocked = true;
|
this._isUnlocked = true;
|
||||||
}
|
}
|
||||||
return this._isUnlocked;
|
return this._isUnlocked;
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
/// <reference path="./Infrastructure.ts" />
|
/// <reference path="./Infrastructure.ts" />
|
||||||
|
|
||||||
class Compound extends Infrastructure {
|
class Compound extends Infrastructure {
|
||||||
constructor () {
|
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 = 15000;
|
this.cost.money = config.cfgCompoundStartingCost;
|
||||||
this._costMultiplier.money = 1.5;
|
this._costMultiplier.money = config.cfgCompoundCostMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
const tents = state.getResource('tents');
|
const tents = state.getResource(ResourceKey.tents);
|
||||||
if (tents.value >= 5) {
|
if (tents !== null && tents.value >= state.config.cfgTentStartingMax) {
|
||||||
this._isUnlocked = true;
|
this._isUnlocked = true;
|
||||||
}
|
}
|
||||||
return this._isUnlocked;
|
return this._isUnlocked;
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
/// <reference path="./Passive.ts" />
|
/// <reference path="./Passive.ts" />
|
||||||
|
|
||||||
class Credibility extends Passive {
|
class Credibility extends Passive {
|
||||||
constructor () {
|
constructor (config: GameConfig) {
|
||||||
super(
|
super(
|
||||||
'Credibility',
|
'Credibility',
|
||||||
'Affects your ability to recruit and retain followers.');
|
'Affects your ability to recruit and retain followers.');
|
||||||
this.value = 100;
|
this.value = config.cfgPassiveMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
public max: (state: GameState) => number = (_state) => 100;
|
public max: (state: GameState) => number = (state) =>
|
||||||
|
state.config.cfgPassiveMax;
|
||||||
|
|
||||||
public inc: (state: GameState) => number = (state) =>
|
public inc: (state: GameState) => number = (state) =>
|
||||||
state.config.cfgCredibilityRestoreRate;
|
state.config.cfgCredibilityRestoreRate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
/// <reference path="./Purchasable.ts" />
|
/// <reference path="./Purchasable.ts" />
|
||||||
|
|
||||||
class CryptoCurrency extends Purchasable {
|
class CryptoCurrency extends Purchasable {
|
||||||
constructor () {
|
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 = 100;
|
this.cost.money = config.cfgCryptoStartingCost;
|
||||||
this._costMultiplier.money = 1.1;
|
this._costMultiplier.money = config.cfgCryptoCostMultiplier;
|
||||||
this.valueInWholeNumbers = false;
|
this.valueInWholeNumbers = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public max: (state: GameState) => number = (state) =>
|
public max: (state: GameState) => number = (state) =>
|
||||||
state.config.cfgStartingCryptoMax;
|
state.config.cfgCryptoStartingMax;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
/// <reference path="./Infrastructure.ts" />
|
/// <reference path="./Infrastructure.ts" />
|
||||||
|
|
||||||
class House extends Infrastructure {
|
class House extends Infrastructure {
|
||||||
constructor () {
|
constructor (config: GameConfig) {
|
||||||
super('Houses',
|
super('Houses',
|
||||||
'Provides room to house 10 followers.');
|
`Provides room to house ${config.formatNumber(config.cfgHouseFollowerCapacity)} followers.`);
|
||||||
this.cost.money = 75000;
|
this.cost.money = config.cfgHouseStartingCost;
|
||||||
this._costMultiplier.money = 1.01;
|
this._costMultiplier.money = config.cfgHouseCostMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
// two houses per compound
|
|
||||||
public max: (state: GameState) => number = (state) =>
|
public max: (state: GameState) => number = (state) =>
|
||||||
state.getResource('cmpnd').value * 2;
|
(state.getResource(ResourceKey.compounds)?.value ?? 0)
|
||||||
|
* state.config.cfgCompoundHouseCapacity;
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
const compounds = state.getResource('cmpnd');
|
const compounds = state.getResource(ResourceKey.compounds);
|
||||||
if (compounds.value > 0) {
|
if (compounds !== null && compounds.value > 0) {
|
||||||
this._isUnlocked = true;
|
this._isUnlocked = true;
|
||||||
}
|
}
|
||||||
return this._isUnlocked;
|
return this._isUnlocked;
|
||||||
|
|
|
@ -7,6 +7,28 @@ enum ResourceType {
|
||||||
passive = 'passive',
|
passive = 'passive',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ResourceKey {
|
||||||
|
playerOrg = 'plorg',
|
||||||
|
christianity = 'xtian',
|
||||||
|
islam = 'islam',
|
||||||
|
hinduism = 'hindu',
|
||||||
|
buddhism = 'buddh',
|
||||||
|
sikhism = 'sikhi',
|
||||||
|
judaism = 'judah',
|
||||||
|
other = 'other',
|
||||||
|
atheism = 'agnos',
|
||||||
|
pastors = 'pstor',
|
||||||
|
money = 'money',
|
||||||
|
faithCoin = 'crpto',
|
||||||
|
tents = 'tents',
|
||||||
|
houses = 'houses',
|
||||||
|
churches = 'chrch',
|
||||||
|
compounds = 'cmpnd',
|
||||||
|
buildingPermit = 'blpmt',
|
||||||
|
megaChurches = 'mchch',
|
||||||
|
credibility = 'creds',
|
||||||
|
}
|
||||||
|
|
||||||
interface IResource {
|
interface IResource {
|
||||||
readonly resourceType: ResourceType;
|
readonly resourceType: ResourceType;
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
|
@ -17,7 +39,7 @@ interface IResource {
|
||||||
// readonly altClickText?: string;
|
// readonly altClickText?: string;
|
||||||
// readonly altClickDescription?: string;
|
// readonly altClickDescription?: string;
|
||||||
readonly value: number;
|
readonly value: number;
|
||||||
readonly cost: { [key: string]: number } | null;
|
readonly cost: { [key in ResourceKey]?: number } | null;
|
||||||
|
|
||||||
max: ((state: GameState) => number) | null;
|
max: ((state: GameState) => number) | null;
|
||||||
inc: ((state: GameState) => number) | null;
|
inc: ((state: GameState) => number) | null;
|
||||||
|
|
|
@ -6,12 +6,12 @@ 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: string]: number } = { };
|
public readonly cost: { [key in ResourceKey]?: number } = { };
|
||||||
|
|
||||||
public max: ((state: GameState) => number) | null = null;
|
public max: ((state: GameState) => number) | null = null;
|
||||||
public inc: ((state: GameState) => number) | null = null;
|
public inc: ((state: GameState) => number) | null = null;
|
||||||
|
|
||||||
protected _costMultiplier: { [key: string]: number } = { };
|
protected _costMultiplier: { [key in ResourceKey]?: number } = { };
|
||||||
protected _isUnlocked = false;
|
protected _isUnlocked = false;
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
@ -29,8 +29,10 @@ abstract class Job implements IResource {
|
||||||
&& state.deductCost(this.cost)) {
|
&& state.deductCost(this.cost)) {
|
||||||
this.addValue(1);
|
this.addValue(1);
|
||||||
state.log(this._hireLog(1, state));
|
state.log(this._hireLog(1, state));
|
||||||
for (const rkey of Object.keys(this._costMultiplier)) {
|
for (const key in this._costMultiplier) {
|
||||||
this.cost[rkey] *= this._costMultiplier[rkey];
|
const rkey = <ResourceKey>key;
|
||||||
|
this.cost[rkey] =
|
||||||
|
(this.cost[rkey] ?? 0) * (this._costMultiplier[rkey] ?? 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,11 +51,11 @@ abstract class Job implements IResource {
|
||||||
|
|
||||||
protected _availableJobs (state: GameState): number {
|
protected _availableJobs (state: GameState): number {
|
||||||
// number of followers minus the number of filled jobs
|
// number of followers minus the number of filled jobs
|
||||||
const followers = state.getResource('plorg').value;
|
const followers = state.getResource(ResourceKey.playerOrg)?.value ?? 0;
|
||||||
const hired = state.getResources().reduce(
|
const hired = state.getResources().reduce(
|
||||||
(tot: number, rkey: string): number => {
|
(tot: number, rkey: ResourceKey): number => {
|
||||||
const res = state.getResource(rkey);
|
const res = state.getResource(rkey);
|
||||||
return res.resourceType === ResourceType.job
|
return res?.resourceType === ResourceType.job
|
||||||
? tot + res.value
|
? tot + res.value
|
||||||
: tot;
|
: tot;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
/// <reference path="./Infrastructure.ts" />
|
/// <reference path="./Infrastructure.ts" />
|
||||||
|
|
||||||
class MegaChurch extends Infrastructure {
|
class MegaChurch extends Infrastructure {
|
||||||
constructor () {
|
constructor (config: GameConfig) {
|
||||||
super('MegaChurches',
|
super('MegaChurches',
|
||||||
'Room for 5 pastors');
|
`Room for ${config.formatNumber(config.cfgMegaChurchPastorCapacity)} pastors`);
|
||||||
this.cost.money = 7500000;
|
this.cost.money = config.cfgMegaChurchStartingCost;
|
||||||
this._costMultiplier.money = 1.01;
|
this._costMultiplier.money = config.cfgMegaChurchCostMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public max: (state: GameState) => number = (state) =>
|
public max: (state: GameState) => number = (state) =>
|
||||||
state.config.cfgStartingMegaChurchMax;
|
state.config.cfgMegaChurchStartingMax;
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
const permit = state.getResource('blpmt');
|
const permit = state.getResource(ResourceKey.buildingPermit);
|
||||||
if (permit.value > 0) {
|
if (permit !== null && permit.value > 0) {
|
||||||
this._isUnlocked = true;
|
this._isUnlocked = true;
|
||||||
}
|
}
|
||||||
return this._isUnlocked;
|
return this._isUnlocked;
|
||||||
|
|
|
@ -16,8 +16,9 @@ class Money extends Purchasable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public max: (state: GameState) => number = (state: GameState) => {
|
public max: (state: GameState) => number = (state: GameState) => {
|
||||||
let max = state.config.cfgStartingMoneyMax;
|
let max = state.config.cfgMoneyStartingMax;
|
||||||
max += state.getResource('cmpnd').value * 500000;
|
max += (state.getResource(ResourceKey.compounds)?.value ?? 0)
|
||||||
|
* state.config.cfgCompoundMoneyCapacity;
|
||||||
return max;
|
return max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,31 +26,32 @@ class Money extends Purchasable {
|
||||||
let inc = 0;
|
let inc = 0;
|
||||||
|
|
||||||
// crypto currency
|
// crypto currency
|
||||||
inc += state.getResource('crpto').value
|
inc += (state.getResource(ResourceKey.faithCoin)?.value ?? 0)
|
||||||
* state.config.cfgCryptoReturnAmount;
|
* state.config.cfgCryptoReturnAmount;
|
||||||
|
|
||||||
|
// TODO: job salaries
|
||||||
|
|
||||||
return inc;
|
return inc;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected _purchaseAmount (state: GameState): number {
|
protected _purchaseAmount (state: GameState): number {
|
||||||
const plorg = state.getResource('plorg');
|
const plorg = state.getResource(ResourceKey.playerOrg);
|
||||||
if (plorg.value === 0) {
|
if (plorg === null || plorg.value === 0) {
|
||||||
state.log('You have no followers to collect from!');
|
state.log('You have no followers to collect from!');
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const diff = state.now - this._lastCollectionTime;
|
const diff = state.now - this._lastCollectionTime;
|
||||||
if (diff < state.config.cfgTimeBetweenTithes) {
|
if (diff < state.config.cfgTimeBetweenTithes) {
|
||||||
const lost = state.config.cfgTimeBetweenTithes / diff / 3;
|
const lost = state.config.cfgTimeBetweenTithes / diff / 3;
|
||||||
state.getResource('creds').addValue(lost * -1, state);
|
state.getResource(ResourceKey.credibility)?.addValue(lost * -1, state);
|
||||||
}
|
}
|
||||||
// each follower gives you $10
|
|
||||||
const tithings = plorg.value * state.config.cfgTitheAmount;
|
const tithings = plorg.value * state.config.cfgTitheAmount;
|
||||||
this._lastCollectionTime = state.now;
|
this._lastCollectionTime = state.now;
|
||||||
return tithings;
|
return tithings;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _purchaseLog (amount: number, state: GameState): string {
|
protected _purchaseLog (amount: number, state: GameState): string {
|
||||||
const followers = state.getResource('plorg').value;
|
const followers = state.getResource(ResourceKey.playerOrg)?.value ?? 0;
|
||||||
return `You collected $${state.formatNumber(amount)} from ${state.formatNumber(followers)} followers.`;
|
return `You collected $${state.config.formatNumber(amount)} from ${state.config.formatNumber(followers)} followers.`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,32 +9,36 @@ class Pastor extends Job {
|
||||||
}
|
}
|
||||||
|
|
||||||
public max: (state: GameState) => number = (state) => {
|
public max: (state: GameState) => number = (state) => {
|
||||||
let max = state.getResource('chrch').value * 2;
|
let max = (state.getResource(ResourceKey.churches)?.value ?? 0)
|
||||||
max += state.getResource('mchch').value * 5;
|
* state.config.cfgChurchPastorCapacity;
|
||||||
|
max += (state.getResource(ResourceKey.megaChurches)?.value ?? 0)
|
||||||
|
* state.config.cfgMegaChurchPastorCapacity;
|
||||||
return max;
|
return max;
|
||||||
};
|
};
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
this._isUnlocked = state.getResource('chrch').isUnlocked(state);
|
this._isUnlocked = state.getResource(
|
||||||
|
ResourceKey.churches)?.isUnlocked(state) === true;
|
||||||
return this._isUnlocked;
|
return this._isUnlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public advanceAction (time: number, state: GameState): void {
|
public advanceAction (time: number, state: GameState): void {
|
||||||
this._timeSinceLastTithe += time;
|
this._timeSinceLastTithe += time;
|
||||||
if (this._timeSinceLastTithe >= state.config.cfgTimeBetweenTithes) {
|
if (this._timeSinceLastTithe >= state.config.cfgTimeBetweenTithes) {
|
||||||
const money = state.getResource('money');
|
const money = state.getResource(ResourceKey.money);
|
||||||
const plorg = state.getResource('plorg');
|
const plorg = state.getResource(ResourceKey.playerOrg);
|
||||||
// each pastor can collect from up to 100 followers
|
let tithed = this.value
|
||||||
let tithed = this.value * 100;
|
* state.config.cfgPastorTitheCollectionFollowerMax;
|
||||||
if (Math.floor(plorg.value) < tithed)
|
if (Math.floor(plorg?.value ?? 0) < tithed)
|
||||||
tithed = Math.floor(plorg.value);
|
tithed = Math.floor(plorg?.value ?? 0);
|
||||||
let collected = tithed * state.config.cfgTitheAmount;
|
let collected = tithed * state.config.cfgTitheAmount;
|
||||||
if (money.max !== null && collected > money.max(state) - money.value)
|
if (money?.max !== null
|
||||||
collected = money.max(state) - money.value;
|
&& collected > (money?.max(state) ?? 0) - (money?.value ?? 0))
|
||||||
|
collected = (money?.max(state) ?? 0) - (money?.value ?? 0);
|
||||||
if (collected > 0) {
|
if (collected > 0) {
|
||||||
money.addValue(collected, state);
|
money?.addValue(collected, state);
|
||||||
state.log(`Your pastors collected $${state.formatNumber(collected)} in tithings from ${state.formatNumber(tithed)} followers.`);
|
state.log(`Your pastors collected $${state.config.formatNumber(collected)} in tithings from ${state.config.formatNumber(tithed)} followers.`);
|
||||||
}
|
}
|
||||||
this._timeSinceLastTithe = 0;
|
this._timeSinceLastTithe = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,15 @@ class PlayerOrg implements IResource {
|
||||||
|
|
||||||
private _timeSinceLastLost = 0;
|
private _timeSinceLastLost = 0;
|
||||||
private _lastRecruitmentLog = 0;
|
private _lastRecruitmentLog = 0;
|
||||||
private _followerSources: { [key: string]: number } = { };
|
private _followerSources: { [key in ResourceKey]?: number } = { };
|
||||||
private _followerDests: { [key: string]: number } = { };
|
private _followerDests: { [key in ResourceKey]?: number } = { };
|
||||||
|
|
||||||
public max (state: GameState): number {
|
public max (state: GameState): number {
|
||||||
let max = state.config.cfgStartingPlayerMax;
|
let max = state.config.cfgFollowerStartingMax;
|
||||||
max += state.getResource('tents').value * 2;
|
max += (state.getResource(ResourceKey.tents)?.value ?? 0)
|
||||||
max += state.getResource('house').value * 10;
|
* state.config.cfgTentFollowerCapacity;
|
||||||
|
max += (state.getResource(ResourceKey.houses)?.value ?? 0)
|
||||||
|
* state.config.cfgHouseFollowerCapacity;
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,12 +28,13 @@ class PlayerOrg implements IResource {
|
||||||
let inc = 0;
|
let inc = 0;
|
||||||
|
|
||||||
// pastor recruiting
|
// pastor recruiting
|
||||||
const pastors = state.getResource('pstor').value;
|
const pastors = state.getResource(ResourceKey.pastors)?.value ?? 0;
|
||||||
inc += pastors * state.config.cfgPastorRecruitRate;
|
inc += pastors * state.config.cfgPastorRecruitRate;
|
||||||
|
|
||||||
// credibility adjustment
|
// credibility adjustment
|
||||||
const creds = state.getResource('creds');
|
const creds = state.getResource(ResourceKey.credibility);
|
||||||
if (creds.max !== null) inc *= creds.value / creds.max(state);
|
if (creds?.max !== null) inc *=
|
||||||
|
(creds?.value ?? 0) / (creds?.max(state) ?? state.config.cfgPassiveMax);
|
||||||
|
|
||||||
return inc;
|
return inc;
|
||||||
}
|
}
|
||||||
|
@ -44,9 +47,10 @@ class PlayerOrg implements IResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
// chance to fail increases as credibility decreases
|
// chance to fail increases as credibility decreases
|
||||||
const creds = state.getResource('creds');
|
const creds = state.getResource(ResourceKey.credibility);
|
||||||
if (creds.max !== null) {
|
if (creds?.max !== null) {
|
||||||
const ratio = Math.ceil(creds.value) / creds.max(state);
|
const ratio = Math.ceil(creds?.value ?? 0) / (creds?.max(state)
|
||||||
|
?? state.config.cfgPassiveMax);
|
||||||
if (Math.random() > ratio) {
|
if (Math.random() > ratio) {
|
||||||
state.log('Your recruitment efforts failed.');
|
state.log('Your recruitment efforts failed.');
|
||||||
return;
|
return;
|
||||||
|
@ -66,21 +70,21 @@ class PlayerOrg implements IResource {
|
||||||
// gained followers must come from other faiths
|
// gained followers must come from other faiths
|
||||||
for (let i = 0; i < diff; i++) {
|
for (let i = 0; i < diff; i++) {
|
||||||
const source = this._getRandomReligion(state);
|
const source = this._getRandomReligion(state);
|
||||||
|
if (source !== null) {
|
||||||
source[1].addValue(-1, state);
|
source[1].addValue(-1, state);
|
||||||
const curFollowers = this._followerSources[source[0]];
|
const curFollowers = this._followerSources[source[0]] ?? 0;
|
||||||
this._followerSources[source[0]] = !isNaN(curFollowers)
|
this._followerSources[source[0]] = curFollowers + 1;
|
||||||
? curFollowers + 1
|
}
|
||||||
: 1;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// lost followers must return to other faiths
|
// lost followers must return to other faiths
|
||||||
for (let i = 0; i < diff * -1; i++) {
|
for (let i = 0; i < diff * -1; i++) {
|
||||||
const dest = this._getRandomReligion(state);
|
const dest = this._getRandomReligion(state);
|
||||||
|
if (dest !== null) {
|
||||||
dest[1].addValue(1, state);
|
dest[1].addValue(1, state);
|
||||||
const curFollowers = this._followerDests[dest[0]];
|
const curFollowers = this._followerDests[dest[0]] ?? 0;
|
||||||
this._followerDests[dest[0]] = !isNaN(curFollowers)
|
this._followerDests[dest[0]] = curFollowers + 1;
|
||||||
? curFollowers + 1
|
}
|
||||||
: 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,13 +96,17 @@ class PlayerOrg implements IResource {
|
||||||
public advanceAction (time: number, state: GameState): void {
|
public advanceAction (time: number, state: GameState): void {
|
||||||
// chance to lose some followers every 10s if credibility < 100%
|
// chance to lose some followers every 10s if credibility < 100%
|
||||||
this._timeSinceLastLost += time;
|
this._timeSinceLastLost += time;
|
||||||
if (this._timeSinceLastLost > 10000) {
|
if (this._timeSinceLastLost > state.config.cfgCredibilityFollowerLossTime) {
|
||||||
if (this.value > 0) {
|
if (this.value > 0) {
|
||||||
const creds = state.getResource('creds');
|
const creds = state.getResource(ResourceKey.credibility);
|
||||||
if (creds.max !== null) {
|
if (creds?.max !== null) {
|
||||||
const ratio = Math.ceil(creds.value) / creds.max(state);
|
const ratio =
|
||||||
|
Math.ceil(creds?.value ?? 0) / (creds?.max(state)
|
||||||
|
?? state.config.cfgPassiveMax);
|
||||||
if (Math.random() > ratio) {
|
if (Math.random() > ratio) {
|
||||||
const lost = Math.ceil(this.value / 25 * (1 - ratio));
|
const lost = Math.ceil(this.value
|
||||||
|
* state.config.cfgCredibilityFollowerLossRatio
|
||||||
|
* (1 - ratio));
|
||||||
this.addValue(lost * -1, state);
|
this.addValue(lost * -1, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,42 +115,54 @@ class PlayerOrg implements IResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
// log lost and gained followers every 10s
|
// log lost and gained followers every 10s
|
||||||
if (state.now - this._lastRecruitmentLog > 10000
|
if (state.now
|
||||||
|
- this._lastRecruitmentLog > state.config.cfgFollowerGainLossLogTimer
|
||||||
&& (Object.keys(this._followerSources).length > 0
|
&& (Object.keys(this._followerSources).length > 0
|
||||||
|| Object.keys(this._followerDests).length > 0)) {
|
|| Object.keys(this._followerDests).length > 0)) {
|
||||||
if (Object.keys(this._followerDests).length > 0) {
|
if (Object.keys(this._followerDests).length > 0) {
|
||||||
let msg = '';
|
let msg = '';
|
||||||
let total = 0;
|
let total = 0;
|
||||||
for (const rkey of Object.keys(this._followerDests)) {
|
for (const key in this._followerDests) {
|
||||||
if (msg !== '') msg += ', ';
|
const rkey = <ResourceKey>key;
|
||||||
const religion = state.getResource(rkey);
|
const religion = state.getResource(rkey);
|
||||||
msg += `${state.formatNumber(this._followerDests[rkey])} to ${religion.name}`;
|
const followers = this._followerDests[rkey];
|
||||||
total += this._followerDests[rkey];
|
if (religion !== null && followers !== undefined) {
|
||||||
|
if (msg !== '') msg += ', ';
|
||||||
|
msg += `${state.config.formatNumber(followers)} to ${religion.name}`;
|
||||||
|
total += followers;
|
||||||
delete this._followerDests[rkey];
|
delete this._followerDests[rkey];
|
||||||
}
|
}
|
||||||
state.log(`You lost ${state.formatNumber(total)} followers: ${msg}`);
|
}
|
||||||
|
state.log(`You lost ${state.config.formatNumber(total)} followers: ${msg}`);
|
||||||
}
|
}
|
||||||
if (Object.keys(this._followerSources).length > 0) {
|
if (Object.keys(this._followerSources).length > 0) {
|
||||||
let msg = '';
|
let msg = '';
|
||||||
let total = 0;
|
let total = 0;
|
||||||
for (const rkey of Object.keys(this._followerSources)) {
|
for (const key in this._followerSources) {
|
||||||
if (msg !== '') msg += ', ';
|
const rkey = <ResourceKey>key;
|
||||||
const religion = state.getResource(rkey);
|
const religion = state.getResource(rkey);
|
||||||
|
const followers = this._followerSources[rkey];
|
||||||
|
if (religion !== null && followers !== undefined) {
|
||||||
|
if (msg !== '') msg += ', ';
|
||||||
msg +=
|
msg +=
|
||||||
`${state.formatNumber(this._followerSources[rkey])} from ${religion.name}`;
|
`${state.config.formatNumber(followers)} from ${religion.name}`;
|
||||||
total += this._followerSources[rkey];
|
total += followers;
|
||||||
delete this._followerSources[rkey];
|
delete this._followerSources[rkey];
|
||||||
}
|
}
|
||||||
state.log(`You gained ${state.formatNumber(total)} followers: ${msg}`);
|
}
|
||||||
|
state.log(`You gained ${state.config.formatNumber(total)} followers: ${msg}`);
|
||||||
}
|
}
|
||||||
this._lastRecruitmentLog = state.now;
|
this._lastRecruitmentLog = state.now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getRandomReligion (state: GameState): [string, IResource] {
|
private _getRandomReligion (
|
||||||
const religs = ['xtian', 'islam', 'hindu',
|
state: GameState): [ResourceKey, IResource] | null {
|
||||||
'buddh', 'sikhi', 'judah', 'other', 'agnos'];
|
const religs = [ResourceKey.christianity, ResourceKey.islam,
|
||||||
|
ResourceKey.hinduism, ResourceKey.buddhism, ResourceKey.sikhism,
|
||||||
|
ResourceKey.judaism, ResourceKey.other, ResourceKey.atheism];
|
||||||
const source = religs[Math.floor(Math.random() * 8)];
|
const source = religs[Math.floor(Math.random() * 8)];
|
||||||
return [source, state.getResource(source)];
|
const resource = state.getResource(source);
|
||||||
|
return resource !== null ? [source, resource] : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: string]: number } = { };
|
public readonly cost: { [key in ResourceKey]?: number } = { };
|
||||||
|
|
||||||
public inc: ((state: GameState) => number) | null = null;
|
public inc: ((state: GameState) => number) | null = null;
|
||||||
public max: ((_state: GameState) => number) | null = null;
|
public max: ((_state: GameState) => number) | null = null;
|
||||||
|
|
||||||
protected _costMultiplier: { [key: string]: number } = { };
|
protected _costMultiplier: { [key in ResourceKey]?: number } = { };
|
||||||
protected _isUnlocked = false;
|
protected _isUnlocked = false;
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
@ -27,8 +27,10 @@ abstract class Purchasable implements IResource {
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
this.value += amount;
|
this.value += amount;
|
||||||
state.log(this._purchaseLog(amount, state));
|
state.log(this._purchaseLog(amount, state));
|
||||||
for (const rkey of Object.keys(this._costMultiplier)) {
|
for (const key in this._costMultiplier) {
|
||||||
this.cost[rkey] *= this._costMultiplier[rkey];
|
const rkey = <ResourceKey>key;
|
||||||
|
this.cost[rkey] =
|
||||||
|
(this.cost[rkey] ?? 0) * (this._costMultiplier[rkey] ?? 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
/// <reference path="./Infrastructure.ts" />
|
/// <reference path="./Infrastructure.ts" />
|
||||||
|
|
||||||
class Tent extends Infrastructure {
|
class Tent extends Infrastructure {
|
||||||
constructor () {
|
constructor (config: GameConfig) {
|
||||||
super('Tents',
|
super('Tents',
|
||||||
'Provides room to house 2 followers.');
|
`Provides room to house ${config.formatNumber(config.cfgTentFollowerCapacity)} followers.`);
|
||||||
this.cost.money = 250;
|
this.cost.money = config.cfgTentStartingCost;
|
||||||
this._costMultiplier.money = 1.05;
|
this._costMultiplier.money = config.cfgTentCostMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
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.cfgStartingTentMax;
|
let max = state.config.cfgTentStartingMax;
|
||||||
max += state.getResource('cmpnd').value * 10;
|
max += (state.getResource(ResourceKey.compounds)?.value ?? 0)
|
||||||
|
* state.config.cfgCompoundTentCapacity;
|
||||||
return max;
|
return max;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ class DebugRenderer implements IRenderer {
|
||||||
private _handleClick = true;
|
private _handleClick = true;
|
||||||
|
|
||||||
public render (state: GameState): void {
|
public render (state: GameState): void {
|
||||||
const rkeys: string[] = state.getResources();
|
const rkeys = state.getResources();
|
||||||
const container = document.getElementById('irreligious-game');
|
const container = document.getElementById('irreligious-game');
|
||||||
if (!this._initialized) {
|
if (!this._initialized) {
|
||||||
if (container === null) {
|
if (container === null) {
|
||||||
|
@ -42,7 +42,8 @@ class DebugRenderer implements IRenderer {
|
||||||
}
|
}
|
||||||
// create containers for each resource
|
// create containers for each resource
|
||||||
for (const rkey of rkeys) {
|
for (const rkey of rkeys) {
|
||||||
const resource: IResource = state.getResource(rkey);
|
const resource = state.getResource(rkey);
|
||||||
|
if (resource === null) continue;
|
||||||
const resContainer = document.getElementById(
|
const resContainer = document.getElementById(
|
||||||
`resource-container-${resource.resourceType}`);
|
`resource-container-${resource.resourceType}`);
|
||||||
if (resContainer === null) continue;
|
if (resContainer === null) continue;
|
||||||
|
@ -70,8 +71,7 @@ class DebugRenderer implements IRenderer {
|
||||||
el.innerHTML = content;
|
el.innerHTML = content;
|
||||||
resContainer.appendChild(el);
|
resContainer.appendChild(el);
|
||||||
if (resource.clickAction !== null) {
|
if (resource.clickAction !== null) {
|
||||||
const btn: Element =
|
const btn = el.getElementsByClassName('resource-btn')[0];
|
||||||
el.getElementsByClassName('resource-btn')[0];
|
|
||||||
btn.addEventListener('click', (): void => {
|
btn.addEventListener('click', (): void => {
|
||||||
state.performClick(rkey);
|
state.performClick(rkey);
|
||||||
});
|
});
|
||||||
|
@ -92,38 +92,34 @@ class DebugRenderer implements IRenderer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (const rkey of rkeys) {
|
for (const rkey of rkeys) {
|
||||||
const resource: IResource = state.getResource(rkey);
|
const resource = state.getResource(rkey);
|
||||||
|
if (resource === null) continue;
|
||||||
const el = document.getElementById(`resource-details-${rkey}`);
|
const el = document.getElementById(`resource-details-${rkey}`);
|
||||||
if (el !== null && resource.isUnlocked(state)) {
|
if (el !== null && resource.isUnlocked(state)) {
|
||||||
if (el.className !== 'resource') el.className = 'resource';
|
if (el.className !== 'resource') el.className = 'resource';
|
||||||
const elV: Element =
|
const elV = el.getElementsByClassName('resource-value')[0];
|
||||||
el.getElementsByClassName('resource-value')[0];
|
const elT = el.getElementsByClassName('resource-max')[0];
|
||||||
const elT: Element =
|
const value = resource.valueInWholeNumbers
|
||||||
el.getElementsByClassName('resource-max')[0];
|
|
||||||
const value: number = resource.valueInWholeNumbers
|
|
||||||
? Math.floor(resource.value)
|
? Math.floor(resource.value)
|
||||||
: resource.value;
|
: resource.value;
|
||||||
elV.innerHTML = state.formatNumber(value);
|
elV.innerHTML = state.config.formatNumber(value);
|
||||||
elT.innerHTML = resource.max !== null
|
elT.innerHTML = resource.max !== null
|
||||||
? ` / ${state.formatNumber(resource.max(state))}`
|
? ` / ${state.config.formatNumber(resource.max(state))}`
|
||||||
: '';
|
: '';
|
||||||
const elB: HTMLCollectionOf<Element> =
|
const elB = el.getElementsByClassName('resource-btn');
|
||||||
el.getElementsByClassName('resource-btn');
|
|
||||||
if (elB.length > 0) {
|
if (elB.length > 0) {
|
||||||
const enabled: boolean = state.isPurchasable(resource.cost)
|
const enabled = state.isPurchasable(resource.cost)
|
||||||
&& (resource.max === null || resource.value < resource.max(state));
|
&& (resource.max === null || resource.value < resource.max(state));
|
||||||
if (enabled) elB[0].removeAttribute('disabled');
|
if (enabled) elB[0].removeAttribute('disabled');
|
||||||
else elB[0].setAttribute('disabled', 'disabled');
|
else elB[0].setAttribute('disabled', 'disabled');
|
||||||
}
|
}
|
||||||
if (resource.inc !== null && resource.inc(state) > 0) {
|
if (resource.inc !== null && resource.inc(state) > 0) {
|
||||||
const elI: Element =
|
const elI = el.getElementsByClassName('resource-inc')[0];
|
||||||
el.getElementsByClassName('resource-inc')[0];
|
|
||||||
elI.innerHTML =
|
elI.innerHTML =
|
||||||
` +${state.formatNumber(resource.inc(state))}/s`;
|
` +${state.config.formatNumber(resource.inc(state))}/s`;
|
||||||
}
|
}
|
||||||
if (this._handleClick) {
|
if (this._handleClick) {
|
||||||
const elC: HTMLCollectionOf<Element> =
|
const elC = el.getElementsByClassName('resource-cost');
|
||||||
el.getElementsByClassName('resource-cost');
|
|
||||||
if (elC.length > 0) {
|
if (elC.length > 0) {
|
||||||
elC[0].innerHTML = this._getCostStr(resource, state);
|
elC[0].innerHTML = this._getCostStr(resource, state);
|
||||||
}
|
}
|
||||||
|
@ -152,15 +148,14 @@ class DebugRenderer implements IRenderer {
|
||||||
|
|
||||||
private _getCostStr (resource: IResource, state: GameState): string {
|
private _getCostStr (resource: IResource, state: GameState): string {
|
||||||
let cost = '';
|
let cost = '';
|
||||||
if (resource.cost !== null) {
|
|
||||||
for (const rkey of state.getResources()) {
|
for (const rkey of state.getResources()) {
|
||||||
if (isNaN(resource.cost[rkey])) continue;
|
if (resource.cost?.[rkey] !== undefined) {
|
||||||
if (cost !== '') cost += ', ';
|
if (cost !== '') cost += ', ';
|
||||||
if (rkey === 'money') {
|
if (rkey === ResourceKey.money) {
|
||||||
cost += `$${state.formatNumber(resource.cost[rkey])}`;
|
cost += `$${state.config.formatNumber(resource.cost[rkey] ?? 0)}`;
|
||||||
} else {
|
} else {
|
||||||
cost += `${state.formatNumber(resource.cost[rkey])}
|
cost += `${state.config.formatNumber(resource.cost[rkey] ?? 0)}
|
||||||
${state.getResource(rkey).name}`;
|
${state.getResource(rkey)?.name ?? rkey}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue