This repository has been archived on 2022-01-16. You can view files and clone it, but cannot push or open issues or pull requests.
irreligious/src/model/resource/Follower.ts

200 lines
6.3 KiB
TypeScript
Raw Normal View History

2021-08-21 19:08:49 -05:00
/// <reference path="./IResource.ts" />
2021-08-21 17:06:51 -05:00
class Follower implements IResource {
public readonly resourceType = ResourceType.religion;
2021-09-06 08:51:41 -05:00
public readonly label = 'Your Followers';
public readonly singularName = 'follower';
public readonly pluralName = 'followers';
public readonly description = 'In you they trust.';
public readonly valueInWholeNumbers = true;
2021-09-04 22:21:14 -05:00
public value = 0;
2021-08-21 17:06:51 -05:00
public userActions: ResourceAction[] = [
{
name: 'Recruit',
description: 'Gather new followers.',
isEnabled: (state: GameState): boolean => this.value < this.max(state),
performAction: (state: GameState): void => {
this._recruitFollower(state);
},
},
];
2021-09-04 22:21:14 -05:00
private _timeSinceLastLost = 0;
private _lastRecruitmentLog = 0;
private _followerSources: ResourceNumber = {};
private _followerDests: ResourceNumber = {};
2021-08-21 17:06:51 -05:00
public max(state: GameState): number {
let max = state.config.cfgInitialMax.followers ?? 0;
max +=
(state.resource.tents?.value ?? 0) *
(state.config.cfgCapacity.tents?.followers ?? 0);
max +=
(state.resource.houses?.value ?? 0) *
(state.config.cfgCapacity.houses?.followers ?? 0);
2021-08-21 19:53:43 -05:00
return max;
2021-08-21 19:02:57 -05:00
}
public inc(state: GameState): number {
2021-09-04 22:21:14 -05:00
let inc = 0;
2021-08-22 13:08:41 -05:00
// pastor recruiting
const pastors = state.resource.pastors?.value ?? 0;
2021-08-22 13:08:41 -05:00
inc += pastors * state.config.cfgPastorRecruitRate;
// credibility adjustment
const creds = state.resource.credibility;
2021-09-05 19:20:24 -05:00
if (creds?.max !== undefined) inc *= creds.value / creds.max(state);
2021-08-22 13:08:41 -05:00
return inc;
}
public addValue(amount: number, state: GameState): void {
2021-09-05 14:45:37 -05:00
const oldValue = this.value;
this.value += amount;
2021-09-05 14:45:37 -05:00
const diff = Math.floor(this.value) - Math.floor(oldValue);
2021-08-22 13:08:41 -05:00
if (diff > 0) {
// gained followers must come from other faiths
2021-09-04 22:21:14 -05:00
for (let i = 0; i < diff; i++) {
2021-09-05 14:45:37 -05:00
const source = this._getRandomReligion(state);
if (source !== null) {
source[1].addValue(-1, state);
const curFollowers = this._followerSources[source[0]] ?? 0;
this._followerSources[source[0]] = curFollowers + 1;
}
2021-08-22 13:08:41 -05:00
}
} else {
// lost followers must return to other faiths
2021-09-04 22:21:14 -05:00
for (let i = 0; i < diff * -1; i++) {
const dest = this._getRandomReligion(state);
if (dest !== null) {
dest[1].addValue(1, state);
const curFollowers = this._followerDests[dest[0]] ?? 0;
this._followerDests[dest[0]] = curFollowers + 1;
}
2021-08-22 13:08:41 -05:00
}
}
}
2021-08-22 11:07:49 -05:00
public isUnlocked(_state: GameState): boolean {
return true;
2021-08-22 11:07:49 -05:00
}
public advanceAction(time: number, state: GameState): void {
2021-08-21 19:02:57 -05:00
// chance to lose some followers every 10s if credibility < 100%
2021-08-22 13:08:41 -05:00
this._timeSinceLastLost += time;
if (this._timeSinceLastLost > state.config.cfgCredibilityFollowerLossTime) {
2021-08-21 19:02:57 -05:00
if (this.value > 0) {
const creds = state.resource.credibility;
2021-09-05 19:20:24 -05:00
if (creds?.max !== undefined) {
const ratio = Math.ceil(creds.value) / creds.max(state);
2021-09-05 14:45:37 -05:00
if (Math.random() > ratio) {
const lost = Math.ceil(
this.value *
state.config.cfgCredibilityFollowerLossRatio *
(1 - ratio)
);
2021-09-05 14:45:37 -05:00
this.addValue(lost * -1, state);
}
2021-08-21 19:02:57 -05:00
}
2021-08-21 17:06:51 -05:00
}
2021-08-22 13:08:41 -05:00
this._timeSinceLastLost = 0;
}
// log lost and gained followers every 10s
if (
state.now - this._lastRecruitmentLog >
state.config.cfgFollowerGainLossLogTimer &&
(Object.keys(this._followerSources).length > 0 ||
Object.keys(this._followerDests).length > 0)
) {
2021-08-22 13:08:41 -05:00
if (Object.keys(this._followerDests).length > 0) {
2021-09-04 22:21:14 -05:00
let msg = '';
let total = 0;
for (const key in this._followerDests) {
const rkey = <ResourceKey>key;
const religion = state.resource[rkey];
const followers = this._followerDests[rkey];
if (religion !== undefined && followers !== undefined) {
if (msg !== '') msg += ', ';
msg += `${formatNumber(followers)} ${
followers > 1 ? religion.pluralName : religion.singularName
}`;
total += followers;
delete this._followerDests[rkey];
}
2021-08-22 13:08:41 -05:00
}
state.log(
`You lost ${formatNumber(total)} ${
total > 1 ? this.pluralName : this.singularName
}: ${msg}`
);
2021-08-22 13:08:41 -05:00
}
if (Object.keys(this._followerSources).length > 0) {
2021-09-04 22:21:14 -05:00
let msg = '';
let total = 0;
for (const key in this._followerSources) {
const rkey = <ResourceKey>key;
const religion = state.resource[rkey];
const followers = this._followerSources[rkey];
if (religion !== undefined && followers !== undefined) {
if (msg !== '') msg += ', ';
msg += `${formatNumber(followers)} ${
followers > 1 ? religion.pluralName : religion.singularName
}`;
total += followers;
delete this._followerSources[rkey];
}
2021-08-22 13:08:41 -05:00
}
state.log(
`You gained ${formatNumber(total)} ${
total > 1 ? this.pluralName : this.singularName
}: ${msg}`
);
2021-08-22 13:08:41 -05:00
}
this._lastRecruitmentLog = state.now;
2021-08-21 17:06:51 -05:00
}
}
private _recruitFollower(state: GameState): void {
// don't exceed max
if (this.value >= this.max(state)) {
state.log('You have no room for more followers.');
return;
}
// chance to fail increases as credibility decreases
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);
}
private _getRandomReligion(
state: GameState
): [ResourceKey, IResource] | null {
const religs = [
ResourceKey.christianity,
ResourceKey.islam,
ResourceKey.hinduism,
ResourceKey.buddhism,
ResourceKey.sikhism,
ResourceKey.judaism,
ResourceKey.other,
ResourceKey.atheism,
];
const source = religs[Math.floor(Math.random() * 8)];
const resource = state.resource[source];
return resource !== undefined ? [source, resource] : null;
2021-08-21 17:06:51 -05:00
}
}