From 3ada82143069605cdf4e62abd72a1ea30936f1b8 Mon Sep 17 00:00:00 2001 From: Rudis Muiznieks Date: Sun, 22 Aug 2021 13:08:41 -0500 Subject: [PATCH] pastor auto recruitment --- public/css/debugger.css | 3 + src/model/resource/Pastor.ts | 3 +- src/model/resource/PlayerOrg.ts | 98 ++++++++++++++++++++++++++------- src/render/DebugRenderer.ts | 76 +++++++++++++------------ 4 files changed, 125 insertions(+), 55 deletions(-) diff --git a/public/css/debugger.css b/public/css/debugger.css index cf30440..6997729 100644 --- a/public/css/debugger.css +++ b/public/css/debugger.css @@ -39,6 +39,9 @@ body, html { padding: 0.25em 0.5em; margin: 0 0.5em 0.5em 0; } +.resource.locked { + display: none; +} #resource-container-religion .resource { background-color: #ccf; } diff --git a/src/model/resource/Pastor.ts b/src/model/resource/Pastor.ts index b75ad26..d009240 100644 --- a/src/model/resource/Pastor.ts +++ b/src/model/resource/Pastor.ts @@ -4,7 +4,8 @@ class Pastor extends Job { private _timeSinceLastTithe: number = 0; 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 { diff --git a/src/model/resource/PlayerOrg.ts b/src/model/resource/PlayerOrg.ts index 5261a1c..10b9971 100644 --- a/src/model/resource/PlayerOrg.ts +++ b/src/model/resource/PlayerOrg.ts @@ -8,12 +8,13 @@ class PlayerOrg implements IResource { public readonly clickText: string = 'Recruit'; public readonly clickDescription: string = 'Gather new followers.'; public value: number = 0; - public readonly cost: { [key: string]: number } = { }; + public readonly cost: null = null; - public readonly inc: null = null; - - private _lastLostTime: number = 0; + private _timeSinceLastLost: number = 0; private _baseMax: number = 5; + private _lastRecruitmentLog: number = 0; + private _followerSources: { [key: string]: number } = { }; + private _followerDests: { [key: string]: number } = { }; public max (state: GameState): number { let max: number = this._baseMax; @@ -22,6 +23,20 @@ class PlayerOrg implements IResource { 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 { // don't exceed max if (this.value >= this.max(state)) { @@ -33,23 +48,39 @@ class PlayerOrg implements IResource { const creds: IResource = state.getResource('creds'); const ratio: number = Math.ceil(creds.value) / creds.max(state); if (Math.random() > ratio) { - state.log('Your recruiting efforts failed.'); + state.log('Your recruitment efforts failed.'); return; } - const source: [string, IResource] = this._getRandomReligion(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.'); - } + this.addValue(1, state); } public addValue (amount: number, state: GameState): void { + const oldValue: number = this.value; 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 { @@ -58,19 +89,48 @@ class PlayerOrg implements IResource { public advanceAction (time: number, state: GameState): void { // 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) { const creds: IResource = state.getResource('creds'); const ratio: number = Math.ceil(creds.value) / creds.max(state); if (Math.random() > ratio) { const lost: number = Math.ceil(this.value / 25 * (1 - ratio)); 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; } } diff --git a/src/render/DebugRenderer.ts b/src/render/DebugRenderer.ts index 1649e41..f213202 100644 --- a/src/render/DebugRenderer.ts +++ b/src/render/DebugRenderer.ts @@ -5,6 +5,7 @@ class DebugRenderer implements IRenderer { private _handleClick: boolean = true; public render (state: GameState): void { + const rkeys: string[] = state.getResources(); if (!this._initialized) { const container: HTMLElement = document.getElementById('irreligious-game'); @@ -36,48 +37,53 @@ class DebugRenderer implements IRenderer { resDiv.appendChild(el); } } + // create containers for each resource + for (const rkey of rkeys) { + const resource: IResource = state.getResource(rkey); + const resContainer: HTMLElement = + document.getElementById( + `resource-container-${resource.resourceType}`); + const el: HTMLElement = document.createElement('div'); + el.className = 'resource locked'; + el.id = `resource-details-${rkey}`; + let content: string = ` + + ${this._escape(resource.name + ? resource.name + : rkey)}
+ + + + `; + if (resource.clickText !== null) { + content += `
+ `; + } + if (resource.cost !== null + && Object.keys(resource.cost).length !== 0) { + content += "
Cost: "; + } + el.innerHTML = content; + resContainer.appendChild(el); + if (resource.clickAction !== null) { + const btn: Element = + el.getElementsByClassName('resource-btn')[0]; + btn.addEventListener('click', (): void => + state.performClick(rkey)); + } + } } - const rkeys: string[] = state.getResources(); for (const rkey of rkeys) { const resource: IResource = state.getResource(rkey); const container: HTMLElement = document .getElementById(`resource-container-${resource.resourceType}`); if (resource.isUnlocked(state)) { - let el: HTMLElement = document + const el: HTMLElement = document .getElementById(`resource-details-${rkey}`); - if (el === null) { - el = document.createElement('div'); - el.className = 'resource'; - el.id = `resource-details-${rkey}`; - let content: string = ` - - ${this._escape(resource.name - ? resource.name - : rkey)}
- - - - `; - if (resource.clickText !== null) { - content += `
- `; - } - if (resource.cost !== null - && Object.keys(resource.cost).length !== 0) { - content += "
Cost: "; - } - el.innerHTML = content; - container.appendChild(el); - if (resource.clickAction !== null) { - const btn: Element = - el.getElementsByClassName('resource-btn')[0]; - btn.addEventListener('click', (): void => - state.performClick(rkey)); - } - } + if (el.className !== 'resource') el.className = 'resource'; const elV: Element = el.getElementsByClassName('resource-value')[0]; const elT: Element =