selling resources and credibility improvements

This commit is contained in:
Rudis Muiznieks 2021-09-06 20:37:23 -05:00
parent dff7d53a75
commit 199db37b01
14 changed files with 86 additions and 23 deletions

View File

@ -79,9 +79,9 @@
## Short-Term Todos ## Short-Term Todos
- [ ] add `disabledHint` to `userActions` to generate hint about how to enable an action - [ ] 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 - [ ] 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 ## Long-Term Ideas

View File

@ -71,6 +71,7 @@ class GameConfig {
public cfgCredibilityFollowerLossTime = 10000; public cfgCredibilityFollowerLossTime = 10000;
public cfgCredibilityRestoreRate = 0.25; public cfgCredibilityRestoreRate = 0.25;
public cfgCryptoReturnAmount = 1; public cfgCryptoReturnAmount = 1;
public cfgDefaultSellMultiplier = 0.5;
public cfgFollowerGainLossLogTimer = 10000; public cfgFollowerGainLossLogTimer = 10000;
public cfgPassiveMax = 100; public cfgPassiveMax = 100;
public cfgPastorRecruitRate = 0.01; public cfgPastorRecruitRate = 0.01;

View File

@ -8,7 +8,10 @@ class Church extends Infrastructure {
'churches', 'churches',
`Preaching grounds for ${formatNumber( `Preaching grounds for ${formatNumber(
config.cfgCapacity.churches?.pastors ?? 0 config.cfgCapacity.churches?.pastors ?? 0
)} pastors.` )} pastors.`,
true,
undefined,
undefined
); );
this.cost.money = config.cfgInitialCost.churches; this.cost.money = config.cfgInitialCost.churches;
this._costMultiplier.money = config.cfgCostMultiplier.churches; this._costMultiplier.money = config.cfgCostMultiplier.churches;

View File

@ -6,7 +6,8 @@ class Compound extends Infrastructure {
'Compounds', 'Compounds',
'compound', 'compound',
'compounds', '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.cost.money = config.cfgInitialCost.compounds;
this._costMultiplier.money = config.cfgCostMultiplier.compounds; this._costMultiplier.money = config.cfgCostMultiplier.compounds;

View File

@ -6,7 +6,7 @@ class Credibility extends Passive {
'Credibility', 'Credibility',
'credibility', 'credibility',
'credibilities', 'credibilities',
'Affects your ability to recruit and retain followers.' 'Affects your ability to retain followers and collect tithes.'
); );
this.value = config.cfgPassiveMax; this.value = config.cfgPassiveMax;
} }

View File

@ -6,7 +6,8 @@ class CryptoCurrency extends Purchasable {
'FaithCoin', 'FaithCoin',
'faithcoin', 'faithcoin',
'faithcoins', '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.cost.money = config.cfgInitialCost.cryptoCurrency;
this._costMultiplier.money = config.cfgCostMultiplier.cryptoCurrency; this._costMultiplier.money = config.cfgCostMultiplier.cryptoCurrency;

View File

@ -44,8 +44,9 @@ class Follower implements IResource {
inc += pastors * state.config.cfgPastorRecruitRate; inc += pastors * state.config.cfgPastorRecruitRate;
// credibility adjustment // credibility adjustment
const creds = state.resource.credibility; // this should be based on notoriety instead
if (creds?.max !== undefined) inc *= creds.value / creds.max(state); /*const creds = state.resource.credibility;
if (creds?.max !== undefined) inc *= creds.value / creds.max(state);*/
return inc; return inc;
} }
@ -119,8 +120,8 @@ class Follower implements IResource {
const followers = this._followerDests[rkey]; const followers = this._followerDests[rkey];
if (religion !== undefined && followers !== undefined) { if (religion !== undefined && followers !== undefined) {
if (msg !== '') msg += ', '; if (msg !== '') msg += ', ';
msg += `${formatNumber(followers)} ${ msg += `${formatNumber(followers)} became ${
followers > 1 ? religion.pluralName : religion.singularName followers > 1 ? religion.pluralName : 'a ' + religion.singularName
}`; }`;
total += followers; total += followers;
delete this._followerDests[rkey]; delete this._followerDests[rkey];
@ -166,14 +167,15 @@ class Follower implements IResource {
} }
// chance to fail increases as credibility decreases // 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) { if (creds?.max !== undefined) {
const ratio = Math.ceil(creds.value) / creds.max(state); const ratio = Math.ceil(creds.value) / creds.max(state);
if (Math.random() > ratio) { if (Math.random() > ratio) {
state.log('Your recruitment efforts failed.'); state.log('Your recruitment efforts failed.');
return; return;
} }
} }*/
this._lastRecruitmentLog = 0; // always log on click this._lastRecruitmentLog = 0; // always log on click
this.addValue(1, state); this.addValue(1, state);

View File

@ -8,7 +8,8 @@ class House extends Infrastructure {
'houses', 'houses',
`Provides room to house ${formatNumber( `Provides room to house ${formatNumber(
config.cfgCapacity.houses?.followers ?? 0 config.cfgCapacity.houses?.followers ?? 0
)} followers.` )} followers.`,
true
); );
this.cost.money = config.cfgInitialCost.houses; this.cost.money = config.cfgInitialCost.houses;
this._costMultiplier.money = config.cfgCostMultiplier.houses; this._costMultiplier.money = config.cfgCostMultiplier.houses;

View File

@ -8,7 +8,8 @@ class Megachurch extends Infrastructure {
'megachurches', 'megachurches',
`Room for ${formatNumber( `Room for ${formatNumber(
config.cfgCapacity.megaChurches?.pastors ?? 0 config.cfgCapacity.megaChurches?.pastors ?? 0
)} pastors` )} pastors`,
true
); );
this.cost.money = config.cfgInitialCost.megaChurches; this.cost.money = config.cfgInitialCost.megaChurches;
this._costMultiplier.money = config.cfgCostMultiplier.megaChurches; this._costMultiplier.money = config.cfgCostMultiplier.megaChurches;

View File

@ -85,9 +85,11 @@ class Money implements IResource {
if (followers !== undefined) { if (followers !== undefined) {
state.log( state.log(
`You collected $${formatNumber(amount)} from ${formatNumber( `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 { } else {

View File

@ -34,11 +34,16 @@ class Pastor extends Job {
if (this._timeSinceLastTithe >= state.config.cfgTimeBetweenTithes) { if (this._timeSinceLastTithe >= state.config.cfgTimeBetweenTithes) {
const money = state.resource.money; const money = state.resource.money;
const followers = state.resource.followers; 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( let tithed = Math.floor(
this.value * state.config.cfgPastorTitheCollectionFollowerMax this.value * state.config.cfgPastorTitheCollectionFollowerMax
); );
if (Math.floor(followers?.value ?? 0) < tithed) if (tithable < tithed) tithed = tithable;
tithed = Math.floor(followers?.value ?? 0);
let collected = tithed * state.config.cfgTitheAmount; let collected = tithed * state.config.cfgTitheAmount;
if ( if (
money?.max !== undefined && money?.max !== undefined &&

View File

@ -23,6 +23,7 @@ abstract class Purchasable implements IResource {
]; ];
protected _costMultiplier: ResourceNumber = {}; protected _costMultiplier: ResourceNumber = {};
protected _sellMultiplier?: number | ResourceNumber;
protected _isUnlocked = false; protected _isUnlocked = false;
constructor( constructor(
@ -30,9 +31,23 @@ abstract class Purchasable implements IResource {
public readonly singularName: string, public readonly singularName: string,
public readonly pluralName: string, public readonly pluralName: string,
public readonly description: string, public readonly description: string,
private readonly _purchaseButtonText: string = 'Purchase', canSell = false,
private readonly _purchaseDescription: string = `Buy a ${singularName}.` 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 { public addValue(amount: number, _state: GameState): void {
this.value += amount; this.value += amount;
@ -50,7 +65,12 @@ abstract class Purchasable implements IResource {
} }
protected _purchaseLog(amount: number, _state: GameState): string { 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 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 = <ResourceKey>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));
}
} }

View File

@ -15,6 +15,7 @@ abstract class Research extends Purchasable {
singularName, singularName,
pluralName, pluralName,
description, description,
false,
'Learn', 'Learn',
'Complete this research.' 'Complete this research.'
); );

View File

@ -8,7 +8,8 @@ class Tent extends Infrastructure {
'tents', 'tents',
`Provides room to house ${formatNumber( `Provides room to house ${formatNumber(
config.cfgCapacity.tents?.followers ?? 0 config.cfgCapacity.tents?.followers ?? 0
)} followers.` )} followers.`,
true
); );
this.cost.money = config.cfgInitialCost.tents; this.cost.money = config.cfgInitialCost.tents;
this._costMultiplier.money = config.cfgCostMultiplier.tents; this._costMultiplier.money = config.cfgCostMultiplier.tents;