diff --git a/TODO.md b/TODO.md index 8a3709f..4f632e2 100644 --- a/TODO.md +++ b/TODO.md @@ -79,9 +79,9 @@ ## Short-Term Todos - [ ] add `disabledHint` to `userActions` to generate hint about how to enable an action -- [ ] add an action to sell purchasables and regain some portion of their cost +- [x] add an action to sell purchasables and regain some portion of their cost - [ ] add a `policy` resource type that can be toggled on or off -- [ ] remove recruitment effects of credibility (that will be for notoriety instead) +- [x] remove recruitment effects of credibility (that will be for notoriety instead) ## Long-Term Ideas diff --git a/src/model/GameConfig.ts b/src/model/GameConfig.ts index 110aa9d..7b43d0c 100644 --- a/src/model/GameConfig.ts +++ b/src/model/GameConfig.ts @@ -71,6 +71,7 @@ class GameConfig { public cfgCredibilityFollowerLossTime = 10000; public cfgCredibilityRestoreRate = 0.25; public cfgCryptoReturnAmount = 1; + public cfgDefaultSellMultiplier = 0.5; public cfgFollowerGainLossLogTimer = 10000; public cfgPassiveMax = 100; public cfgPastorRecruitRate = 0.01; diff --git a/src/model/resource/Church.ts b/src/model/resource/Church.ts index 24986ae..aa9c753 100644 --- a/src/model/resource/Church.ts +++ b/src/model/resource/Church.ts @@ -8,7 +8,10 @@ class Church extends Infrastructure { 'churches', `Preaching grounds for ${formatNumber( config.cfgCapacity.churches?.pastors ?? 0 - )} pastors.` + )} pastors.`, + true, + undefined, + undefined ); this.cost.money = config.cfgInitialCost.churches; this._costMultiplier.money = config.cfgCostMultiplier.churches; diff --git a/src/model/resource/Compound.ts b/src/model/resource/Compound.ts index 8310f4d..27382ff 100644 --- a/src/model/resource/Compound.ts +++ b/src/model/resource/Compound.ts @@ -6,7 +6,8 @@ class Compound extends Infrastructure { 'Compounds', 'compound', '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.', + true ); this.cost.money = config.cfgInitialCost.compounds; this._costMultiplier.money = config.cfgCostMultiplier.compounds; diff --git a/src/model/resource/Credibility.ts b/src/model/resource/Credibility.ts index 0af14e3..8315525 100644 --- a/src/model/resource/Credibility.ts +++ b/src/model/resource/Credibility.ts @@ -6,7 +6,7 @@ class Credibility extends Passive { 'Credibility', 'credibility', 'credibilities', - 'Affects your ability to recruit and retain followers.' + 'Affects your ability to retain followers and collect tithes.' ); this.value = config.cfgPassiveMax; } diff --git a/src/model/resource/CryptoCurrency.ts b/src/model/resource/CryptoCurrency.ts index 4eb2496..4a799a1 100644 --- a/src/model/resource/CryptoCurrency.ts +++ b/src/model/resource/CryptoCurrency.ts @@ -6,7 +6,8 @@ class CryptoCurrency extends Purchasable { 'FaithCoin', 'faithcoin', 'faithcoins', - "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.", + true ); this.cost.money = config.cfgInitialCost.cryptoCurrency; this._costMultiplier.money = config.cfgCostMultiplier.cryptoCurrency; diff --git a/src/model/resource/Follower.ts b/src/model/resource/Follower.ts index 3d3dc26..dc3542c 100644 --- a/src/model/resource/Follower.ts +++ b/src/model/resource/Follower.ts @@ -44,8 +44,9 @@ class Follower implements IResource { inc += pastors * state.config.cfgPastorRecruitRate; // credibility adjustment - const creds = state.resource.credibility; - if (creds?.max !== undefined) inc *= creds.value / creds.max(state); + // this should be based on notoriety instead + /*const creds = state.resource.credibility; + if (creds?.max !== undefined) inc *= creds.value / creds.max(state);*/ return inc; } @@ -119,8 +120,8 @@ class Follower implements IResource { const followers = this._followerDests[rkey]; if (religion !== undefined && followers !== undefined) { if (msg !== '') msg += ', '; - msg += `${formatNumber(followers)} ${ - followers > 1 ? religion.pluralName : religion.singularName + msg += `${formatNumber(followers)} became ${ + followers > 1 ? religion.pluralName : 'a ' + religion.singularName }`; total += followers; delete this._followerDests[rkey]; @@ -166,14 +167,15 @@ class Follower implements IResource { } // chance to fail increases as credibility decreases - const creds = state.resource.credibility; + // this should be based on notoriety instead + /*const creds = state.resource.credibility; if (creds?.max !== undefined) { const ratio = Math.ceil(creds.value) / creds.max(state); if (Math.random() > ratio) { state.log('Your recruitment efforts failed.'); return; } - } + }*/ this._lastRecruitmentLog = 0; // always log on click this.addValue(1, state); diff --git a/src/model/resource/House.ts b/src/model/resource/House.ts index 1797a3d..ae69ca0 100644 --- a/src/model/resource/House.ts +++ b/src/model/resource/House.ts @@ -8,7 +8,8 @@ class House extends Infrastructure { 'houses', `Provides room to house ${formatNumber( config.cfgCapacity.houses?.followers ?? 0 - )} followers.` + )} followers.`, + true ); this.cost.money = config.cfgInitialCost.houses; this._costMultiplier.money = config.cfgCostMultiplier.houses; diff --git a/src/model/resource/Megachurch.ts b/src/model/resource/Megachurch.ts index 0cf9c9d..c8d39ca 100644 --- a/src/model/resource/Megachurch.ts +++ b/src/model/resource/Megachurch.ts @@ -8,7 +8,8 @@ class Megachurch extends Infrastructure { 'megachurches', `Room for ${formatNumber( config.cfgCapacity.megaChurches?.pastors ?? 0 - )} pastors` + )} pastors`, + true ); this.cost.money = config.cfgInitialCost.megaChurches; this._costMultiplier.money = config.cfgCostMultiplier.megaChurches; diff --git a/src/model/resource/Money.ts b/src/model/resource/Money.ts index b80a9a8..88fbe5c 100644 --- a/src/model/resource/Money.ts +++ b/src/model/resource/Money.ts @@ -85,9 +85,11 @@ class Money implements IResource { if (followers !== undefined) { state.log( `You collected $${formatNumber(amount)} from ${formatNumber( - followers.value + Math.floor(followers.value) )} ${ - followers.value > 1 ? followers.pluralName : followers.singularName + Math.floor(followers.value) > 1 + ? followers.pluralName + : followers.singularName }.` ); } else { diff --git a/src/model/resource/Pastor.ts b/src/model/resource/Pastor.ts index 0267d3c..e535fe9 100644 --- a/src/model/resource/Pastor.ts +++ b/src/model/resource/Pastor.ts @@ -34,11 +34,16 @@ class Pastor extends Job { if (this._timeSinceLastTithe >= state.config.cfgTimeBetweenTithes) { const money = state.resource.money; const followers = state.resource.followers; + let tithable = Math.floor((followers?.value ?? 0) - this.value); + // bad credibility makes people not tithe + const creds = state.resource.credibility; + if (creds?.max !== undefined) { + tithable = Math.floor(tithable * (creds.value / creds.max(state))); + } let tithed = Math.floor( this.value * state.config.cfgPastorTitheCollectionFollowerMax ); - if (Math.floor(followers?.value ?? 0) < tithed) - tithed = Math.floor(followers?.value ?? 0); + if (tithable < tithed) tithed = tithable; let collected = tithed * state.config.cfgTitheAmount; if ( money?.max !== undefined && diff --git a/src/model/resource/Purchasable.ts b/src/model/resource/Purchasable.ts index f83b0bc..f41c3a2 100644 --- a/src/model/resource/Purchasable.ts +++ b/src/model/resource/Purchasable.ts @@ -23,6 +23,7 @@ abstract class Purchasable implements IResource { ]; protected _costMultiplier: ResourceNumber = {}; + protected _sellMultiplier?: number | ResourceNumber; protected _isUnlocked = false; constructor( @@ -30,9 +31,23 @@ abstract class Purchasable implements IResource { public readonly singularName: string, public readonly pluralName: string, public readonly description: string, - private readonly _purchaseButtonText: string = 'Purchase', - private readonly _purchaseDescription: string = `Buy a ${singularName}.` - ) {} + canSell = false, + private readonly _purchaseButtonText = 'Purchase', + private readonly _purchaseDescription = `Buy a ${singularName}.`, + private readonly _sellButtonText = 'Sell', + private readonly _sellDescription = `Sell a ${singularName}.` + ) { + if (canSell) { + this.userActions.push({ + name: this._sellButtonText, + description: this._sellDescription, + isEnabled: (_state: GameState): boolean => this.value > 0, + performAction: (state: GameState): void => { + this._sell(state); + }, + }); + } + } public addValue(amount: number, _state: GameState): void { this.value += amount; @@ -50,7 +65,12 @@ abstract class Purchasable implements IResource { } protected _purchaseLog(amount: number, _state: GameState): string { - return `You purchased ${amount} ${ + let verb = 'purchased'; + if (amount < 0) { + verb = 'sold'; + amount *= -1; + } + return `You ${verb} ${amount} ${ amount > 1 ? this.pluralName : this.singularName }.`; } @@ -67,4 +87,28 @@ abstract class Purchasable implements IResource { } } } + + private _sell(state: GameState): void { + if (this.value <= 0) return; + const costBack: ResourceNumber = {}; + for (const key in this.cost) { + const rkey = key; + let cost = this.cost[rkey]; + if (cost === undefined) continue; + // revert cost multiplier + cost /= this._costMultiplier[rkey] ?? 1; + this.cost[rkey] = cost; + const multiplier = + this._sellMultiplier === undefined + ? state.config.cfgDefaultSellMultiplier + : typeof this._sellMultiplier === 'number' + ? this._sellMultiplier + : this._sellMultiplier[rkey] ?? state.config.cfgDefaultSellMultiplier; + // penalize return on used item + costBack[rkey] = cost * -1 * multiplier; + state.deductCost(costBack); + } + this.value -= 1; + state.log(this._purchaseLog(-1, state)); + } } diff --git a/src/model/resource/Research.ts b/src/model/resource/Research.ts index 88a1f9a..4d5ef0f 100644 --- a/src/model/resource/Research.ts +++ b/src/model/resource/Research.ts @@ -15,6 +15,7 @@ abstract class Research extends Purchasable { singularName, pluralName, description, + false, 'Learn', 'Complete this research.' ); diff --git a/src/model/resource/Tent.ts b/src/model/resource/Tent.ts index 9786d82..deff908 100644 --- a/src/model/resource/Tent.ts +++ b/src/model/resource/Tent.ts @@ -8,7 +8,8 @@ class Tent extends Infrastructure { 'tents', `Provides room to house ${formatNumber( config.cfgCapacity.tents?.followers ?? 0 - )} followers.` + )} followers.`, + true ); this.cost.money = config.cfgInitialCost.tents; this._costMultiplier.money = config.cfgCostMultiplier.tents;