pastor auto recruitment

This commit is contained in:
Rudis Muiznieks 2021-08-22 13:08:41 -05:00
parent a4ffd985ef
commit 3ada821430
4 changed files with 125 additions and 55 deletions

View File

@ -39,6 +39,9 @@ body, html {
padding: 0.25em 0.5em; padding: 0.25em 0.5em;
margin: 0 0.5em 0.5em 0; margin: 0 0.5em 0.5em 0;
} }
.resource.locked {
display: none;
}
#resource-container-religion .resource { #resource-container-religion .resource {
background-color: #ccf; background-color: #ccf;
} }

View File

@ -4,7 +4,8 @@ class Pastor extends Job {
private _timeSinceLastTithe: number = 0; private _timeSinceLastTithe: number = 0;
constructor () { constructor () {
super('Pastors', 'Leaders of the faith.'); super('Pastors',
'Collect tithings for you and recruit new members from other faiths automatically.');
} }
public max (state: GameState): number { public max (state: GameState): number {

View File

@ -8,12 +8,13 @@ class PlayerOrg implements IResource {
public readonly clickText: string = 'Recruit'; public readonly clickText: string = 'Recruit';
public readonly clickDescription: string = 'Gather new followers.'; public readonly clickDescription: string = 'Gather new followers.';
public value: number = 0; public value: number = 0;
public readonly cost: { [key: string]: number } = { }; public readonly cost: null = null;
public readonly inc: null = null; private _timeSinceLastLost: number = 0;
private _lastLostTime: number = 0;
private _baseMax: number = 5; private _baseMax: number = 5;
private _lastRecruitmentLog: number = 0;
private _followerSources: { [key: string]: number } = { };
private _followerDests: { [key: string]: number } = { };
public max (state: GameState): number { public max (state: GameState): number {
let max: number = this._baseMax; let max: number = this._baseMax;
@ -22,6 +23,20 @@ class PlayerOrg implements IResource {
return max; return max;
} }
public inc (state: GameState): number {
let inc: number = 0;
// pastor recruiting
const pastors: number = state.getResource('pstor').value;
inc += pastors * state.config.cfgPastorRecruitRate;
// credibility adjustment
const creds: IResource = state.getResource('creds');
inc *= creds.value / creds.max(state);
return inc;
}
public clickAction (state: GameState): void { public clickAction (state: GameState): void {
// don't exceed max // don't exceed max
if (this.value >= this.max(state)) { if (this.value >= this.max(state)) {
@ -33,23 +48,39 @@ class PlayerOrg implements IResource {
const creds: IResource = state.getResource('creds'); const creds: IResource = state.getResource('creds');
const ratio: number = Math.ceil(creds.value) / creds.max(state); const ratio: number = Math.ceil(creds.value) / creds.max(state);
if (Math.random() > ratio) { if (Math.random() > ratio) {
state.log('Your recruiting efforts failed.'); state.log('Your recruitment efforts failed.');
return; return;
} }
const source: [string, IResource] = this._getRandomReligion(state); this.addValue(1, state);
this.cost[source[0]] = 1;
if (state.deductCost(this.cost)) {
this.value++;
delete this.cost[source[0]];
state.log(`You converted one new follower from ${source[1].name}!`);
} else {
state.log('Your recruiting efforts failed.');
}
} }
public addValue (amount: number, state: GameState): void { public addValue (amount: number, state: GameState): void {
const oldValue: number = this.value;
this.value += amount; this.value += amount;
const diff: number = Math.floor(this.value) - Math.floor(oldValue);
if (diff > 0) {
// gained followers must come from other faiths
for (let i: number = 0; i < diff; i++) {
const source: [string, IResource] = this._getRandomReligion(state);
source[1].addValue(-1, state);
const curFollowers: number = this._followerSources[source[0]];
this._followerSources[source[0]] = curFollowers
? curFollowers + 1
: 1;
}
} else {
// lost followers must return to other faiths
for (let i: number = 0; i < diff * -1; i++) {
const dest: [string, IResource] = this._getRandomReligion(state);
dest[1].addValue(1, state);
const curFollowers: number = this._followerDests[dest[0]];
this._followerDests[dest[0]] = curFollowers
? curFollowers + 1
: 1;
}
}
} }
public isUnlocked (state: GameState): boolean { public isUnlocked (state: GameState): boolean {
@ -58,19 +89,48 @@ class PlayerOrg implements IResource {
public advanceAction (time: number, state: GameState): void { public advanceAction (time: number, state: GameState): void {
// chance to lose some followers every 10s if credibility < 100% // chance to lose some followers every 10s if credibility < 100%
if (state.now - this._lastLostTime > 10000) { this._timeSinceLastLost += time;
if (this._timeSinceLastLost > 10000) {
if (this.value > 0) { if (this.value > 0) {
const creds: IResource = state.getResource('creds'); const creds: IResource = state.getResource('creds');
const ratio: number = Math.ceil(creds.value) / creds.max(state); const ratio: number = Math.ceil(creds.value) / creds.max(state);
if (Math.random() > ratio) { if (Math.random() > ratio) {
const lost: number = Math.ceil(this.value / 25 * (1 - ratio)); const lost: number = Math.ceil(this.value / 25 * (1 - ratio));
this.addValue(lost * -1, state); this.addValue(lost * -1, state);
const dest: [string, IResource] = this._getRandomReligion(state);
dest[1].addValue(lost, state);
state.log(`You lost ${lost} followers to ${dest[1].name}.`);
} }
} }
this._lastLostTime = state.now; this._timeSinceLastLost = 0;
}
// log lost and gained followers every 10s
if (state.now - this._lastRecruitmentLog > 10000
&& (Object.keys(this._followerSources).length > 0
|| Object.keys(this._followerDests).length > 0)) {
if (Object.keys(this._followerDests).length > 0) {
let msg: string;
for (const rkey of Object.keys(this._followerDests)) {
if (msg === undefined) msg = 'You lost ';
else msg += ' and ';
const religion: IResource = state.getResource(rkey);
msg +=
`${state.formatNumber(this._followerDests[rkey])} followers to ${religion.name}`;
delete this._followerDests[rkey];
}
state.log(msg);
}
if (Object.keys(this._followerSources).length > 0) {
let msg: string;
for (const rkey of Object.keys(this._followerSources)) {
if (msg === undefined) msg = 'You gained ';
else msg += ' and ';
const religion: IResource = state.getResource(rkey);
msg +=
`${state.formatNumber(this._followerSources[rkey])} followers from ${religion.name}`;
delete this._followerSources[rkey];
}
state.log(msg);
}
this._lastRecruitmentLog = state.now;
} }
} }

View File

@ -5,6 +5,7 @@ class DebugRenderer implements IRenderer {
private _handleClick: boolean = true; private _handleClick: boolean = true;
public render (state: GameState): void { public render (state: GameState): void {
const rkeys: string[] = state.getResources();
if (!this._initialized) { if (!this._initialized) {
const container: HTMLElement = const container: HTMLElement =
document.getElementById('irreligious-game'); document.getElementById('irreligious-game');
@ -36,18 +37,14 @@ class DebugRenderer implements IRenderer {
resDiv.appendChild(el); resDiv.appendChild(el);
} }
} }
} // create containers for each resource
const rkeys: string[] = state.getResources();
for (const rkey of rkeys) { for (const rkey of rkeys) {
const resource: IResource = state.getResource(rkey); const resource: IResource = state.getResource(rkey);
const container: HTMLElement = document const resContainer: HTMLElement =
.getElementById(`resource-container-${resource.resourceType}`); document.getElementById(
if (resource.isUnlocked(state)) { `resource-container-${resource.resourceType}`);
let el: HTMLElement = document const el: HTMLElement = document.createElement('div');
.getElementById(`resource-details-${rkey}`); el.className = 'resource locked';
if (el === null) {
el = document.createElement('div');
el.className = 'resource';
el.id = `resource-details-${rkey}`; el.id = `resource-details-${rkey}`;
let content: string = ` let content: string = `
<span class='resource-title' <span class='resource-title'
@ -70,7 +67,7 @@ class DebugRenderer implements IRenderer {
content += "<br>Cost: <span class='resource-cost'></span>"; content += "<br>Cost: <span class='resource-cost'></span>";
} }
el.innerHTML = content; el.innerHTML = content;
container.appendChild(el); resContainer.appendChild(el);
if (resource.clickAction !== null) { if (resource.clickAction !== null) {
const btn: Element = const btn: Element =
el.getElementsByClassName('resource-btn')[0]; el.getElementsByClassName('resource-btn')[0];
@ -78,6 +75,15 @@ class DebugRenderer implements IRenderer {
state.performClick(rkey)); state.performClick(rkey));
} }
} }
}
for (const rkey of rkeys) {
const resource: IResource = state.getResource(rkey);
const container: HTMLElement = document
.getElementById(`resource-container-${resource.resourceType}`);
if (resource.isUnlocked(state)) {
const el: HTMLElement = document
.getElementById(`resource-details-${rkey}`);
if (el.className !== 'resource') el.className = 'resource';
const elV: Element = const elV: Element =
el.getElementsByClassName('resource-value')[0]; el.getElementsByClassName('resource-value')[0];
const elT: Element = const elT: Element =