diff --git a/.gitignore b/.gitignore index fd39b89..e5a6635 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ public/js/irreligious.js node_modules/* +.env diff --git a/README.md b/README.md index c4e9fff..24a413e 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,15 @@ An incremental game in which you start a cult and must grow it into the dominant ## Current State -It can be run and played through a not-very-pretty debugging interface. To make testing easier, default configuration is massively sped up from what the final game will use, and the relationships between resources have not been play-tested or balanced in any meaningful way. +Playable, but lightyears from complete and not very pretty or fun yet. -## Build and Run +## Play Online + +[https://irreligio.us/](https://irreligio.us) + +The online version may be behind what's in the repository. + +## Build and Run Locally ``` npm install diff --git a/package.json b/package.json index 831f42e..aad4b7a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,8 @@ { "scripts": { - "build": "eslint src/ && tsc", - "lint": "eslint src/" + "lint": "eslint src/", + "build": "npm run lint && tsc", + "deploy": "aws s3 sync --delete public/ \"$(grep AWS_S3_BUCKET .env | cut -d '=' -f2)\" && aws cloudfront create-invalidation --distribution-id \"$(grep AWS_CLOUDFRONT_ID .env | cut -d '=' -f2)\" --paths=/*" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "^4.30.0", diff --git a/src/model/GameConfig.ts b/src/model/GameConfig.ts index b35b6b8..5c7a93c 100644 --- a/src/model/GameConfig.ts +++ b/src/model/GameConfig.ts @@ -77,6 +77,7 @@ class GameConfig { public cfgPastorTitheCollectionFollowerMax = 100; public cfgTimeBetweenTithes = 30000; public cfgTitheAmount = 10; + public cfgTitheCredibilityHitFactor = 3; public generateState (): GameState { const state = new GameState(this); diff --git a/src/model/resource/Money.ts b/src/model/resource/Money.ts index f97552c..e0f5864 100644 --- a/src/model/resource/Money.ts +++ b/src/model/resource/Money.ts @@ -1,22 +1,36 @@ /// -class Money extends Purchasable { +class Money implements IResource { public readonly resourceType = ResourceType.consumable; + public readonly label = 'Money'; + public readonly singularName = '${}'; + public readonly pluralName = '${}'; + public readonly description = 'Used to purchase goods and services.'; + public readonly valueInWholeNumbers = false; + + public userActions: ResourceAction[] = [ + { + name: 'Collect Tithes', + description: 'Voluntary contributions from followers.', + isEnabled: (state: GameState): boolean => + this.value <= this.max(state) + && (state.resource.followers?.value ?? 0) >= 1, + performAction: (state: GameState): void => { + this._collectTithes(state); + }, + }, + ]; private _lastCollectionTime = 0; constructor ( public value: number - ) { - super( - 'Money', - '${}', - '${}', - 'Used to purchase goods and services.', - 'Collect Tithes', - 'Voluntary contributions from followers.'); - this.valueInWholeNumbers = false; - this._isUnlocked = true; + ) {} + + public isUnlocked = (_state: GameState): boolean => true; + + public addValue (amount: number, _state: GameState): void { + this.value += amount; } public max: (state: GameState) => number = (state: GameState) => { @@ -40,20 +54,27 @@ class Money extends Purchasable { return inc; }; - protected _purchaseAmount (state: GameState): number { - const plorg = state.resource.followers; - if (plorg === undefined || plorg.value === 0) { - state.log('You have no followers to collect from!'); - return 0; - } + protected _collectTithes (state: GameState): void { + if (this.value >= this.max(state)) return; + + const followers = state.resource.followers?.value ?? 0; + if (followers <= 0) return; + + // collecting too frequently hurts credibility const diff = state.now - this._lastCollectionTime; if (diff < state.config.cfgTimeBetweenTithes) { - const lost = state.config.cfgTimeBetweenTithes / diff / 3; + const lost = state.config.cfgTimeBetweenTithes + / diff / state.config.cfgTitheCredibilityHitFactor; state.resource.credibility?.addValue(lost * -1, state); } - const tithings = plorg.value * state.config.cfgTitheAmount; + + const tithings = followers * state.config.cfgTitheAmount; this._lastCollectionTime = state.now; - return tithings; + + if (tithings > 0) { + this.addValue(tithings, state); + this._purchaseLog(tithings, state); + } } protected _purchaseLog (amount: number, state: GameState): string { diff --git a/src/model/resource/Purchasable.ts b/src/model/resource/Purchasable.ts index 831757e..58b1de2 100644 --- a/src/model/resource/Purchasable.ts +++ b/src/model/resource/Purchasable.ts @@ -49,10 +49,6 @@ abstract class Purchasable implements IResource { return; } - protected _purchaseAmount (_state: GameState): number { - return 1; - } - protected _purchaseLog (amount: number, _state: GameState): string { return `You purchased ${amount} ${amount > 1 ? this.pluralName : this.singularName}.`; } @@ -60,15 +56,12 @@ abstract class Purchasable implements IResource { private _purchase (state: GameState): void { if (this.max !== undefined && this.value >= this.max(state)) return; if (state.deductCost(this.cost)) { - const amount = this._purchaseAmount(state); - if (amount > 0) { - this.value += amount; - state.log(this._purchaseLog(amount, state)); - for (const key in this._costMultiplier) { - const rkey = key; - this.cost[rkey] = - (this.cost[rkey] ?? 0) * (this._costMultiplier[rkey] ?? 1); - } + this.value += 1; + state.log(this._purchaseLog(1, state)); + for (const key in this._costMultiplier) { + const rkey = key; + this.cost[rkey] = + (this.cost[rkey] ?? 0) * (this._costMultiplier[rkey] ?? 1); } } }