From 079ff29f97ab72d1f18089c3e14daf3ec2ccf9a6 Mon Sep 17 00:00:00 2001 From: Rudis Muiznieks Date: Mon, 6 Sep 2021 22:44:00 -0500 Subject: [PATCH] crypto market hidden resource to drive faithcoin cost --- src/main.ts | 9 ++--- src/model/GameConfig.ts | 10 ++++- src/model/GameState.ts | 10 ++++- src/model/resource/CryptoCurrency.ts | 4 +- src/model/resource/CryptoMarket.ts | 55 ++++++++++++++++++++++++++++ src/model/resource/Hidden.ts | 21 +++++++++++ src/model/resource/Money.ts | 5 --- src/model/resource/Passive.ts | 2 - src/model/resource/SharedTypes.ts | 1 + src/render/DebugRenderer.ts | 2 +- 10 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 src/model/resource/CryptoMarket.ts create mode 100644 src/model/resource/Hidden.ts diff --git a/src/main.ts b/src/main.ts index 7d032d3..d9febc0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,7 @@ /// const versionMajor = 2; -const versionMinor = 0; +const versionMinor = 1; let globalStartTime = 0; let globalTimeout: number | null = null; @@ -45,18 +45,17 @@ The game's source code on Github const config = new GameConfig(versionMajor, versionMinor); // debug values to make the game play faster while testing - config.cfgTitheAmount = 1000; - config.cfgTimeBetweenTithes = 5000; - config.cfgCryptoReturnAmount = 100; config.cfgCredibilityRestoreRate = 5; config.cfgPastorRecruitRate = 0.5; + config.cfgTimeBetweenTithes = 5000; + config.cfgTitheAmount = 1000; const renderer = new DebugRenderer(); renderer.onInitialRender = initialRender; const state = config.generateState(); // re-run main loop immediately on user clicks - state.onResourceClick.push((): void => { + state.onAction.push((): void => { if (globalTimeout !== null) { clearTimeout(globalTimeout); gameLoop(state, renderer); diff --git a/src/model/GameConfig.ts b/src/model/GameConfig.ts index 7b43d0c..9c04cf8 100644 --- a/src/model/GameConfig.ts +++ b/src/model/GameConfig.ts @@ -4,6 +4,7 @@ /// /// /// +/// /// /// /// @@ -29,7 +30,8 @@ class GameConfig { // general configs public cfgInitialMax: ResourceNumber = { - cryptoCurrency: 1000, + cryptoCurrency: 10000, + cryptoMarket: 100000000, megaChurches: 2, money: 500000, followers: 5, @@ -70,7 +72,10 @@ class GameConfig { public cfgCredibilityFollowerLossRatio = 0.04; public cfgCredibilityFollowerLossTime = 10000; public cfgCredibilityRestoreRate = 0.25; - public cfgCryptoReturnAmount = 1; + public cfgCryptoCurrencyMinimumValue = 1; + public cfgCryptoMarketAdjustAmount = 0.1; + public cfgCryptoMarketAdjustPeriod = 30000; + public cfgCryptoMarketGrowthBias = 0.1; public cfgDefaultSellMultiplier = 0.5; public cfgFollowerGainLossLogTimer = 10000; public cfgPassiveMax = 100; @@ -194,6 +199,7 @@ class GameConfig { // add passive resources state.addResource(ResourceKey.credibility, new Credibility(this)); + state.addResource(ResourceKey.cryptoMarket, new CryptoMarket(this)); return state; } diff --git a/src/model/GameState.ts b/src/model/GameState.ts index 1118ae3..2f063f5 100644 --- a/src/model/GameState.ts +++ b/src/model/GameState.ts @@ -3,7 +3,7 @@ class GameState { public readonly config: GameConfig; - public onResourceClick: Array<() => void> = []; + public onAction: Array<() => void> = []; public logger: ILogger | null = null; public now = 0; @@ -70,6 +70,12 @@ class GameState { } } + public autoAction(): void { + for (const callback of this.onAction) { + callback(); + } + } + public performAction(resourceKey: ResourceKey, actionIndex: number): void { const resource = this._resources[resourceKey]; if ( @@ -83,7 +89,7 @@ class GameState { const action = resource.userActions[actionIndex]; action.performAction(this); - for (const callback of this.onResourceClick) { + for (const callback of this.onAction) { callback(); } } diff --git a/src/model/resource/CryptoCurrency.ts b/src/model/resource/CryptoCurrency.ts index 4a799a1..f5f6b4d 100644 --- a/src/model/resource/CryptoCurrency.ts +++ b/src/model/resource/CryptoCurrency.ts @@ -14,6 +14,8 @@ class CryptoCurrency extends Purchasable { this.valueInWholeNumbers = false; } - public max: (state: GameState) => number = (state) => + public isUnlocked = (_state: GameState): boolean => true; + + public max = (state: GameState): number => state.config.cfgInitialMax.cryptoCurrency ?? 0; } diff --git a/src/model/resource/CryptoMarket.ts b/src/model/resource/CryptoMarket.ts new file mode 100644 index 0000000..cfa8c7b --- /dev/null +++ b/src/model/resource/CryptoMarket.ts @@ -0,0 +1,55 @@ +/// + +class CryptoMarket extends Hidden { + private _adjustmentTime = 0; + + constructor(config: GameConfig) { + super( + 'crypto market', + 'crypto markets', + 'How much money a single FaithCoin is worth' + ); + this.value = config.cfgInitialCost.cryptoCurrency ?? 0; + } + + public max = (state: GameState): number => + state.config.cfgInitialMax.cryptoMarket ?? 0; + + public advanceAction = (time: number, state: GameState): void => { + const crypto = state.resource.cryptoCurrency; + if (crypto === undefined) return; + this._adjustmentTime += time; + if (this._adjustmentTime >= state.config.cfgCryptoMarketAdjustPeriod) { + this._adjustmentTime = 0; + let adjustment = + this.value * + state.config.cfgCryptoMarketAdjustAmount * + 2 * + Math.random() - + this.value * state.config.cfgCryptoMarketAdjustAmount; + adjustment += + this.value * + state.config.cfgCryptoMarketAdjustAmount * + Math.random() * + state.config.cfgCryptoMarketGrowthBias; + if ( + this.value + adjustment < + state.config.cfgCryptoCurrencyMinimumValue + ) { + adjustment = state.config.cfgCryptoCurrencyMinimumValue - this.value; + } + //if (Math.abs(adjustment) > 0) { + this.addValue(adjustment, state); + state.log( + `FaithCoin just ${ + adjustment > 0 ? 'increased' : 'decreased' + } in value by $${formatNumber(Math.abs(adjustment))}.` + ); + //} + if (crypto?.cost !== undefined) { + crypto.cost.money = this.value; + state.autoAction(); // cause redraw + } + } + }; +} diff --git a/src/model/resource/Hidden.ts b/src/model/resource/Hidden.ts new file mode 100644 index 0000000..1c7249d --- /dev/null +++ b/src/model/resource/Hidden.ts @@ -0,0 +1,21 @@ +/// + +abstract class Hidden implements IResource { + public readonly resourceType = ResourceType.passive; + public readonly valueInWholeNumbers = false; + public value = 0; + + constructor( + public readonly singularName: string, + public readonly pluralName: string, + public readonly description: string + ) {} + + public addValue(amount: number, _state: GameState): void { + this.value += amount; + } + + public isUnlocked(_state: GameState): boolean { + return true; + } +} diff --git a/src/model/resource/Money.ts b/src/model/resource/Money.ts index 88fbe5c..abe21c8 100644 --- a/src/model/resource/Money.ts +++ b/src/model/resource/Money.ts @@ -42,11 +42,6 @@ class Money implements IResource { public inc: (state: GameState) => number = (state) => { let inc = 0; - // crypto currency - inc += - (state.resource.cryptoCurrency?.value ?? 0) * - state.config.cfgCryptoReturnAmount; - // salaries inc -= (state.resource.pastors?.value ?? 0) * diff --git a/src/model/resource/Passive.ts b/src/model/resource/Passive.ts index 60391e5..c537b6a 100644 --- a/src/model/resource/Passive.ts +++ b/src/model/resource/Passive.ts @@ -5,8 +5,6 @@ abstract class Passive implements IResource { public readonly valueInWholeNumbers = false; public value = 0; - public advanceAction?: (time: number, state: GameState) => void = undefined; - constructor( public readonly label: string, public readonly singularName: string, diff --git a/src/model/resource/SharedTypes.ts b/src/model/resource/SharedTypes.ts index 0484f80..63a2c87 100644 --- a/src/model/resource/SharedTypes.ts +++ b/src/model/resource/SharedTypes.ts @@ -22,6 +22,7 @@ enum ResourceKey { pastors = 'pastors', money = 'money', cryptoCurrency = 'cryptoCurrency', + cryptoMarket = 'cryptoMarket', tents = 'tents', houses = 'houses', churches = 'churches', diff --git a/src/render/DebugRenderer.ts b/src/render/DebugRenderer.ts index fd406ca..6c68479 100644 --- a/src/render/DebugRenderer.ts +++ b/src/render/DebugRenderer.ts @@ -14,7 +14,7 @@ class DebugRenderer implements IRenderer { console.error('could not find game container'); return; } - state.onResourceClick.push((): void => { + state.onAction.push((): void => { this._handleClick = true; }); const style = document.createElement('link');