selling resources and credibility improvements
This commit is contained in:
parent
dff7d53a75
commit
199db37b01
4
TODO.md
4
TODO.md
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 &&
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ abstract class Research extends Purchasable {
|
||||||
singularName,
|
singularName,
|
||||||
pluralName,
|
pluralName,
|
||||||
description,
|
description,
|
||||||
|
false,
|
||||||
'Learn',
|
'Learn',
|
||||||
'Complete this research.'
|
'Complete this research.'
|
||||||
);
|
);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Reference in New Issue