diff --git a/public/css/debugger.css b/public/css/debugger.css index 7cc7c98..af26d36 100644 --- a/public/css/debugger.css +++ b/public/css/debugger.css @@ -1,9 +1,10 @@ .resource-type-container { display: flex; + flex-wrap: wrap; } .resource { + min-width: 8em; border: 2px solid black; - padding: 5px 10px; - margin: 0 5px 5px 0; - flex-shrink: 0; + padding: 0.25em 0.5em; + margin: 0 0.5em 0.5em 0; } diff --git a/src/model/GameConfig.ts b/src/model/GameConfig.ts index 903b7fe..7f684d3 100644 --- a/src/model/GameConfig.ts +++ b/src/model/GameConfig.ts @@ -1,7 +1,6 @@ /// /// /// -/// class GameConfig { public worldPopulation: number = 790000000; @@ -57,8 +56,7 @@ class GameConfig { this.relNoneShare * this.worldPopulation)); // add purchasable resources - state.addResource('money', new Money(0)); - state.addResource('bonds', new Savings(0)); + state.addResource('money', new Money(100)); return state; } diff --git a/src/model/GameState.ts b/src/model/GameState.ts index 0169c34..564e0d7 100644 --- a/src/model/GameState.ts +++ b/src/model/GameState.ts @@ -1,3 +1,4 @@ +/// /// class GameState { @@ -5,6 +6,8 @@ class GameState { private _resourceKeys: string[] = []; public onResourceClick: (() => void)[] = []; + public logger: ILogger = null; + public numberFormatDigits: number = 1; public addResource (key: string, resource: IResource): void { this._resourceKeys.push(key); @@ -12,15 +15,24 @@ class GameState { } public advance (time: number): void { + // advance each resource for (const rkey of this._resourceKeys) { if (this._resources[rkey].advanceAction !== null) { this._resources[rkey].advanceAction(time, this); } - const max: number | null = this._resources[rkey].max(this); - if (this._resources[rkey].inc(this) > 0 - && (max === null || this._resources[rkey].value < max)) { - this._resources[rkey].value += - this._resources[rkey].inc(this) * time / 1000; + } + + // perform auto increments + for (const rkey of this._resourceKeys) { + const max: number = this._resources[rkey].max + ? this._resources[rkey].max(this) + : null; + const inc: number = this._resources[rkey].inc + ? this._resources[rkey].inc(this) + : 0; + if (inc > 0 && (max === null + || this._resources[rkey].value < max)) { + this._resources[rkey].value += inc * time / 1000; } if (max !== null && this._resources[rkey].value > max) { this._resources[rkey].value = max; @@ -63,4 +75,31 @@ class GameState { } return true; } + + public formatNumber (num: number): string { + type vlookup = { value: number, symbol: string }; + const lookup: vlookup[] = [ + { value: 1, symbol: "" }, + { value: 1e3, symbol: "K" }, + { value: 1e6, symbol: "M" }, + { value: 1e9, symbol: "G" }, + { value: 1e12, symbol: "T" }, + { value: 1e15, symbol: "P" }, + { value: 1e18, symbol: "E" } + ]; + const rx: RegExp = /\.0+$|(\.[0-9]*[1-9])0+$/; + const item: vlookup = + lookup.slice().reverse() + .find((i: vlookup): boolean => num >= i.value); + return item + ? (num / item.value).toFixed(this.numberFormatDigits) + .replace(rx, "$1") + item.symbol + : num.toFixed(this.numberFormatDigits).replace(rx, "$1"); + } + + public log (text: string): void { + if (this.logger !== null) { + this.logger.msg(text); + } + } } diff --git a/src/model/logging/ConsoleLogger.ts b/src/model/logging/ConsoleLogger.ts new file mode 100644 index 0000000..8fa5b65 --- /dev/null +++ b/src/model/logging/ConsoleLogger.ts @@ -0,0 +1,7 @@ +/// + +class ConsoleLogger implements ILogger { + public msg (text: string): void { + console.log(text); // tslint:disable-line + } +} diff --git a/src/model/logging/ILogger.ts b/src/model/logging/ILogger.ts new file mode 100644 index 0000000..2ea8fd6 --- /dev/null +++ b/src/model/logging/ILogger.ts @@ -0,0 +1,3 @@ +interface ILogger { + msg (text: string): void; +} diff --git a/src/model/resource/Credibility.ts b/src/model/resource/Credibility.ts new file mode 100644 index 0000000..119c147 --- /dev/null +++ b/src/model/resource/Credibility.ts @@ -0,0 +1,4 @@ +/// + +class Credibility extends Hidden { +} diff --git a/src/model/resource/Hidden.ts b/src/model/resource/Hidden.ts new file mode 100644 index 0000000..83a3ffa --- /dev/null +++ b/src/model/resource/Hidden.ts @@ -0,0 +1,30 @@ +/// + +abstract class Hidden implements IResource { + public readonly resourceType: ResourceType = ResourceType.Hidden; + public readonly clickText: null = null; + public readonly clickDescription: null = null; + public readonly advanceAction: null = null; + public readonly cost: null = null; + public readonly clickAction: null = null; + public readonly name: null = null; + public readonly description: null = null; + + protected _baseMax: number | null = null; + + constructor ( + public value: number + ) { } + + public inc (state: GameState): number | null { + return null; + } + + public max (state: GameState): number | null { + return this._baseMax; + } + + public isUnlocked (state: GameState): boolean { + return true; + } +} diff --git a/src/model/resource/IResource.ts b/src/model/resource/IResource.ts index 9e9bb54..46ef5db 100644 --- a/src/model/resource/IResource.ts +++ b/src/model/resource/IResource.ts @@ -1,24 +1,28 @@ enum ResourceType { Religion = 'religion', Consumable = 'consumable', - Infrastructure = 'infrastructure' + Infrastructure = 'infrastructure', + Hidden = 'hidden' } interface IResource { - name: string; - description: string; + name: string | null; + description: string | null; resourceType: ResourceType; value: number; - max: (state: GameState) => number | null; - inc: (state: GameState) => number | null; - cost: { [key: string]: number }; - - isUnlocked: (state: GameState) => boolean; clickText: string; clickDescription: string; - clickAction: (state: GameState) => void; - advanceAction: (time: number, state: GameState) => void; + clickAction (state: GameState): void; + + cost: { [key: string]: number }; + + max (state: GameState): number | null; + inc (state: GameState): number | null; + + isUnlocked (state: GameState): boolean; + + advanceAction (time: number, state: GameState): void; } diff --git a/src/model/resource/Money.ts b/src/model/resource/Money.ts index 6972d10..eb2121f 100644 --- a/src/model/resource/Money.ts +++ b/src/model/resource/Money.ts @@ -5,19 +5,23 @@ class Money extends Purchasable { public value: number, ) { super('Money', 'Used to purchase goods and services.'); - this.clickText = 'Beg'; - this.clickDescription = 'Alms for the poor.'; - this._baseMax = 1000; + this.clickText = 'Collect Tithes'; + this.clickDescription = 'Voluntary contributions from followers.'; } public isUnlocked (state: GameState): boolean { return true; } - public inc (state: GameState): number { - let baseInc: number = 0; - // bonds give $1/s - baseInc += state.getResource('bonds').value; - return baseInc; + protected _incrementAmount (state: GameState): number { + const plorg: IResource = state.getResource('plorg'); + if (plorg.value === 0) { + state.log('You have no followers to collect from!'); + return 0; + } + // each follower gives you $10 + const tithings: number = plorg.value * 10; + state.log(`You collected $${state.formatNumber(tithings)} from ${state.formatNumber(plorg.value)} followers.`); + return tithings; } } diff --git a/src/model/resource/Purchasable.ts b/src/model/resource/Purchasable.ts index c2f7bc6..2cc9b06 100644 --- a/src/model/resource/Purchasable.ts +++ b/src/model/resource/Purchasable.ts @@ -7,9 +7,9 @@ abstract class Purchasable implements IResource { public clickText: string = 'Purchase'; public clickDescription: string = 'Purchase'; - public cost: { [key: string]: number } = null; + public cost: { [key: string]: number } | null = null; - protected _costMultiplier: { [key: string]: number } = null; + protected _costMultiplier: { [key: string]: number } | null = null; protected _baseMax: number | null = null; constructor ( @@ -20,7 +20,7 @@ abstract class Purchasable implements IResource { public clickAction (state: GameState): void { if (this.max(state) !== null && this.value >= this.max(state)) return; if (state.deductCost(this.cost)) { - this.value += 1; + this.value += this._incrementAmount(state); if (this._costMultiplier !== null && Object.keys(this._costMultiplier !== null)) { for (const rkey of Object.keys(this._costMultiplier)) { @@ -45,4 +45,8 @@ abstract class Purchasable implements IResource { public isUnlocked (state: GameState): boolean { return false; } + + protected _incrementAmount (state: GameState): number { + return 1; + } } diff --git a/src/model/resource/Religion.ts b/src/model/resource/Religion.ts index 1f97936..adc1cfe 100644 --- a/src/model/resource/Religion.ts +++ b/src/model/resource/Religion.ts @@ -2,14 +2,14 @@ class Religion implements IResource { public readonly resourceType: ResourceType = ResourceType.Religion; - public readonly clickText: string = null; - public readonly clickDescription: string = null; - public readonly advanceAction: (time: number) => void = null; - public readonly cost: { [key: string]: number } = null; + public readonly clickText: null = null; + public readonly clickDescription: null = null; + public readonly advanceAction: null = null; + public readonly cost: null = null; - public readonly max: () => null = (): null => null; - public readonly inc: () => null = (): null => null; - public readonly clickAction: () => void = null; + public readonly max: null = null; + public readonly inc: null = null; + public readonly clickAction: null = null; constructor ( public readonly name: string, diff --git a/src/model/resource/Savings.ts b/src/model/resource/Savings.ts deleted file mode 100644 index a4f9ee3..0000000 --- a/src/model/resource/Savings.ts +++ /dev/null @@ -1,26 +0,0 @@ -/// - -class Savings extends Purchasable { - private _isUnlocked: boolean = false; - - constructor ( - public value: number, - ) { - super('Savings', "Can't be spent, but grows money over time."); - this.cost = { 'money': 10 }; - this._costMultiplier = { 'money': 1.1 }; - } - - public isUnlocked (state: GameState): boolean { - if (this._isUnlocked) return true; - if (state.getResource('money').value >= this.cost.money) { - this._isUnlocked = true; - return true; - } - return false; - } - - protected purchaseEffect (state: GameState): void { - return; - } -} diff --git a/src/render/DebugRenderer.ts b/src/render/DebugRenderer.ts index 767ff35..96abbf8 100644 --- a/src/render/DebugRenderer.ts +++ b/src/render/DebugRenderer.ts @@ -1,4 +1,5 @@ /// +/// /// class DebugRenderer implements IRenderer { @@ -7,6 +8,7 @@ class DebugRenderer implements IRenderer { public render (state: GameState): void { if (!this._initialized) { + state.logger = new ConsoleLogger(); const container: HTMLElement = document.getElementById('irreligious-game'); this._initialized = true; @@ -70,16 +72,17 @@ class DebugRenderer implements IRenderer { el.getElementsByClassName('resource-value')[0]; const elT: Element = el.getElementsByClassName('resource-max')[0]; - elV.innerHTML = this.formatNumber(resource.value, 1); - elT.innerHTML = resource.max(state) !== null - ? ` / ${this.formatNumber(resource.max(state), 1)}` + elV.innerHTML = state.formatNumber(resource.value); + elT.innerHTML = resource.max !== null + && resource.max(state) !== null + ? ` / ${state.formatNumber(resource.max(state))}` : ''; if (this._handleClick) { - if (resource.inc(state) > 0) { + if (resource.inc !== null && resource.inc(state) > 0) { const elI: Element = el.getElementsByClassName('resource-inc')[0]; elI.innerHTML = - ` +${this.formatNumber(resource.inc(state), 1)}/s`; + ` +${state.formatNumber(resource.inc(state))}/s`; } const elC: HTMLCollectionOf = el.getElementsByClassName('resource-cost'); @@ -98,33 +101,13 @@ class DebugRenderer implements IRenderer { if (resource.cost[rkey] !== undefined) { if (cost !== '') cost += ', '; if (rkey === 'money') { - cost += `$${this.formatNumber(resource.cost[rkey], 1)}`; + cost += `$${state.formatNumber(resource.cost[rkey])}`; } else { - cost += `${this.formatNumber(resource.cost[rkey], 1)} + cost += `${state.formatNumber(resource.cost[rkey])} ${state.getResource(rkey).name}`; } } } return cost; } - - private formatNumber (num: number, digits: number): string { - type vlookup = { value: number, symbol: string }; - const lookup: vlookup[] = [ - { value: 1, symbol: "" }, - { value: 1e3, symbol: "K" }, - { value: 1e6, symbol: "M" }, - { value: 1e9, symbol: "G" }, - { value: 1e12, symbol: "T" }, - { value: 1e15, symbol: "P" }, - { value: 1e18, symbol: "E" } - ]; - const rx: RegExp = /\.0+$|(\.[0-9]*[1-9])0+$/; - const item: vlookup = - lookup.slice().reverse() - .find((i: vlookup): boolean => num >= i.value); - return item - ? (num / item.value).toFixed(digits).replace(rx, "$1") + item.symbol - : num.toFixed(digits).replace(rx, "$1"); - } } diff --git a/tslint.json b/tslint.json index fe04b0d..78166b7 100644 --- a/tslint.json +++ b/tslint.json @@ -7,7 +7,8 @@ "max-line-length": [ true, { "limit": 75, - "check-strings": true + "check-strings": true, + "ignore-pattern": "\\s+state\\.log\\(" } ], "whitespace": [