fixes for linter
This commit is contained in:
parent
da6aac7003
commit
3e767b396b
|
@ -9,6 +9,10 @@
|
||||||
"parserOptions": {"project": "tsconfig.json"},
|
"parserOptions": {"project": "tsconfig.json"},
|
||||||
"plugins": ["@typescript-eslint"],
|
"plugins": ["@typescript-eslint"],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"max-len": ["warn", {
|
||||||
|
"ignoreStrings": true,
|
||||||
|
"ignoreTemplateLiterals": true,
|
||||||
|
"ignoreRegExpLiterals": true}],
|
||||||
"@typescript-eslint/triple-slash-reference": "off",
|
"@typescript-eslint/triple-slash-reference": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
"@typescript-eslint/no-unused-vars": "off",
|
||||||
"@typescript-eslint/array-type": ["warn", {"default": "array-simple"}],
|
"@typescript-eslint/array-type": ["warn", {"default": "array-simple"}],
|
||||||
|
@ -29,7 +33,6 @@
|
||||||
"@typescript-eslint/no-base-to-string": "error",
|
"@typescript-eslint/no-base-to-string": "error",
|
||||||
"@typescript-eslint/no-confusing-non-null-assertion": "error",
|
"@typescript-eslint/no-confusing-non-null-assertion": "error",
|
||||||
"@typescript-eslint/no-confusing-void-expression": "error",
|
"@typescript-eslint/no-confusing-void-expression": "error",
|
||||||
"@typescript-eslint/no-dynamic-delete": "warn",
|
|
||||||
"@typescript-eslint/no-extraneous-class": "error",
|
"@typescript-eslint/no-extraneous-class": "error",
|
||||||
"@typescript-eslint/no-implicit-any-catch": "error",
|
"@typescript-eslint/no-implicit-any-catch": "error",
|
||||||
"@typescript-eslint/no-invalid-void-type": "error",
|
"@typescript-eslint/no-invalid-void-type": "error",
|
||||||
|
@ -61,12 +64,6 @@
|
||||||
"allowNullableObject": false}],
|
"allowNullableObject": false}],
|
||||||
"@typescript-eslint/switch-exhaustiveness-check": "warn",
|
"@typescript-eslint/switch-exhaustiveness-check": "warn",
|
||||||
"@typescript-eslint/type-annotation-spacing": "warn",
|
"@typescript-eslint/type-annotation-spacing": "warn",
|
||||||
"@typescript-eslint/typedef": ["error", {
|
|
||||||
"arrowParameter": true,
|
|
||||||
"memberVariableDeclaration": true,
|
|
||||||
"parameter": true,
|
|
||||||
"propertyDeclaration": true,
|
|
||||||
"variableDeclaration": true}],
|
|
||||||
"@typescript-eslint/unified-signatures": "warn",
|
"@typescript-eslint/unified-signatures": "warn",
|
||||||
"@typescript-eslint/brace-style": "warn",
|
"@typescript-eslint/brace-style": "warn",
|
||||||
"@typescript-eslint/comma-dangle": ["warn", "always-multiline"],
|
"@typescript-eslint/comma-dangle": ["warn", "always-multiline"],
|
||||||
|
@ -74,7 +71,17 @@
|
||||||
"@typescript-eslint/default-param-last": "error",
|
"@typescript-eslint/default-param-last": "error",
|
||||||
"@typescript-eslint/dot-notation": "error",
|
"@typescript-eslint/dot-notation": "error",
|
||||||
"@typescript-eslint/func-call-spacing": ["warn", "never"],
|
"@typescript-eslint/func-call-spacing": ["warn", "never"],
|
||||||
"@typescript-eslint/indent": ["warn", 2],
|
"@typescript-eslint/indent": ["warn", 2, {
|
||||||
|
"SwitchCase": 1,
|
||||||
|
"VariableDeclarator": 1,
|
||||||
|
"outerIIFEBody": 1,
|
||||||
|
"FunctionDeclaration": {"parameters": 1, "body": 1},
|
||||||
|
"CallExpression": {"arguments": 1},
|
||||||
|
"ArrayExpression": 1,
|
||||||
|
"ObjectExpression": 1,
|
||||||
|
"MemberExpression": 2,
|
||||||
|
"flatTernaryExpressions": false,
|
||||||
|
"ignoreComments": false}],
|
||||||
"@typescript-eslint/keyword-spacing": "error",
|
"@typescript-eslint/keyword-spacing": "error",
|
||||||
"@typescript-eslint/lines-between-class-members": ["warn", "always", {
|
"@typescript-eslint/lines-between-class-members": ["warn", "always", {
|
||||||
"exceptAfterSingleLine": true}],
|
"exceptAfterSingleLine": true}],
|
||||||
|
|
12
src/main.ts
12
src/main.ts
|
@ -2,7 +2,7 @@
|
||||||
/// <reference path="./render/DebugRenderer.ts" />
|
/// <reference path="./render/DebugRenderer.ts" />
|
||||||
|
|
||||||
let globalStartTime = 0;
|
let globalStartTime = 0;
|
||||||
let globalTimeout: number = null;
|
let globalTimeout: number | null = null;
|
||||||
const cycleLength = 250;
|
const cycleLength = 250;
|
||||||
|
|
||||||
function gameLoop (state: GameState, renderer: IRenderer): void {
|
function gameLoop (state: GameState, renderer: IRenderer): void {
|
||||||
|
@ -15,8 +15,9 @@ function gameLoop (state: GameState, renderer: IRenderer): void {
|
||||||
|
|
||||||
// run again in 1sec
|
// run again in 1sec
|
||||||
globalStartTime = new Date().getTime();
|
globalStartTime = new Date().getTime();
|
||||||
globalTimeout = setTimeout((): void =>
|
globalTimeout = setTimeout((): void => {
|
||||||
gameLoop(state, renderer), cycleLength);
|
gameLoop(state, renderer);
|
||||||
|
}, cycleLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
function startGame (state: GameState, renderer: IRenderer): void {
|
function startGame (state: GameState, renderer: IRenderer): void {
|
||||||
|
@ -47,6 +48,7 @@ function startGame (state: GameState, renderer: IRenderer): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (document.readyState !== 'loading') startGame(state, renderer);
|
if (document.readyState !== 'loading') startGame(state, renderer);
|
||||||
else document.addEventListener('DOMContentLoaded', (): void =>
|
else document.addEventListener('DOMContentLoaded', (): void => {
|
||||||
startGame(state, renderer));
|
startGame(state, renderer);
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -25,15 +25,20 @@ class GameConfig {
|
||||||
public relOtherShare = 0.02;
|
public relOtherShare = 0.02;
|
||||||
public relNoneShare = 0.16;
|
public relNoneShare = 0.16;
|
||||||
|
|
||||||
|
public cfgStartingPlayerMax = 5;
|
||||||
|
public cfgStartingMoneyMax = 500000;
|
||||||
|
public cfgStartingTentMax = 5;
|
||||||
|
public cfgStartingCryptoMax = 1000;
|
||||||
|
public cfgStartingMegaChurchMax = 2;
|
||||||
|
|
||||||
public cfgTitheAmount = 10;
|
public cfgTitheAmount = 10;
|
||||||
public cfgTimeBetweenTithes = 30000;
|
public cfgTimeBetweenTithes = 30000;
|
||||||
public cfgCryptoReturnAmount = 1;
|
public cfgCryptoReturnAmount = 1;
|
||||||
public cfgCredibilityRestoreRate = 0.25;
|
public cfgCredibilityRestoreRate = 0.25;
|
||||||
public cfgPastorRecruitRate= 0.01;
|
public cfgPastorRecruitRate = 0.01;
|
||||||
|
|
||||||
public generateState (): GameState {
|
public generateState (): GameState {
|
||||||
const state: GameState = new GameState();
|
const state: GameState = new GameState(this);
|
||||||
state.config = this;
|
|
||||||
|
|
||||||
// create player organization
|
// create player organization
|
||||||
state.addResource('plorg', new PlayerOrg());
|
state.addResource('plorg', new PlayerOrg());
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
class GameState {
|
class GameState {
|
||||||
|
public readonly config: GameConfig;
|
||||||
|
|
||||||
|
public onResourceClick: Array<() => void> = [];
|
||||||
|
public logger: ILogger | null = null;
|
||||||
|
public numberFormatDigits = 1;
|
||||||
|
|
||||||
|
public now = 0;
|
||||||
|
|
||||||
private readonly _versionMaj: number = 0;
|
private readonly _versionMaj: number = 0;
|
||||||
private readonly _versionMin: number = 1;
|
private readonly _versionMin: number = 1;
|
||||||
|
|
||||||
public config: GameConfig;
|
|
||||||
|
|
||||||
private _timeSinceSave = 0;
|
private _timeSinceSave = 0;
|
||||||
private readonly _timeBetweenSaves: number = 10000;
|
private readonly _timeBetweenSaves: number = 10000;
|
||||||
|
|
||||||
private _resources: {[key: string]: IResource} = { };
|
private _resources: { [key: string]: IResource } = { };
|
||||||
private _resourceKeys: string[] = [];
|
private readonly _resourceKeys: string[] = [];
|
||||||
|
|
||||||
public onResourceClick: Array<() => void> = [];
|
|
||||||
public logger: ILogger = null;
|
|
||||||
public numberFormatDigits = 1;
|
|
||||||
|
|
||||||
public now = 0;
|
constructor (config: GameConfig) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
public addResource (key: string, resource: IResource): void {
|
public addResource (key: string, resource: IResource): void {
|
||||||
this._resourceKeys.push(key);
|
this._resourceKeys.push(key);
|
||||||
|
@ -32,32 +37,29 @@ class GameState {
|
||||||
|
|
||||||
// advance each resource
|
// advance each resource
|
||||||
for (const rkey of this._resourceKeys) {
|
for (const rkey of this._resourceKeys) {
|
||||||
if (this._resources[rkey].isUnlocked(this)
|
const resource = this._resources[rkey];
|
||||||
&& this._resources[rkey].advanceAction !== null) {
|
if (this._resources[rkey].isUnlocked(this)) {
|
||||||
this._resources[rkey].advanceAction(time, this);
|
if (resource.advanceAction !== null)
|
||||||
|
resource.advanceAction(time, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform auto increments
|
// perform auto increments
|
||||||
for (const rkey of this._resourceKeys) {
|
for (const rkey of this._resourceKeys) {
|
||||||
if (!this._resources[rkey].isUnlocked(this)) continue;
|
const resource = this._resources[rkey];
|
||||||
|
if (!resource.isUnlocked(this)) continue;
|
||||||
|
|
||||||
const max: number = this._resources[rkey].max
|
if (resource.inc !== null && (resource.max === null
|
||||||
? this._resources[rkey].max(this)
|
|| this._resources[rkey].value < resource.max(this))) {
|
||||||
: null;
|
this._resources[rkey].addValue(resource.inc(this) * time / 1000, this);
|
||||||
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].addValue(inc * time / 1000, this);
|
|
||||||
}
|
}
|
||||||
const val: number = this._resources[rkey].value;
|
|
||||||
if (max !== null && val > max) {
|
if (resource.max !== null && resource.value > resource.max(this)) {
|
||||||
this._resources[rkey].addValue((val - max) * -1, this);
|
this._resources[rkey].addValue(
|
||||||
|
(resource.value - resource.max(this)) * -1, this);
|
||||||
}
|
}
|
||||||
if (val < 0) {
|
if (resource.value < 0) {
|
||||||
this._resources[rkey].addValue(val * -1, this);
|
this._resources[rkey].addValue(resource.value * -1, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,18 +73,19 @@ class GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public performClick (resourceKey: string): void {
|
public performClick (resourceKey: string): void {
|
||||||
if (!this._resources[resourceKey].isUnlocked(this)) return;
|
const resource = this._resources[resourceKey];
|
||||||
|
if (!resource.isUnlocked(this)) return;
|
||||||
|
|
||||||
if (this._resources[resourceKey].clickAction !== null) {
|
if (resource.clickAction !== null) {
|
||||||
this._resources[resourceKey].clickAction(this);
|
resource.clickAction(this);
|
||||||
for (const callback of this.onResourceClick) {
|
for (const callback of this.onResourceClick) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public deductCost (cost: { [rkey: string]: number }): boolean {
|
public deductCost (cost: { [rkey: string]: number } | null): boolean {
|
||||||
if (cost === null || Object.keys(cost) === null) return true;
|
if (cost === null) return true;
|
||||||
if (!this.isPurchasable(cost)) return false;
|
if (!this.isPurchasable(cost)) return false;
|
||||||
for (const rkey of Object.keys(cost)) {
|
for (const rkey of Object.keys(cost)) {
|
||||||
this._resources[rkey].addValue(cost[rkey] * -1, this);
|
this._resources[rkey].addValue(cost[rkey] * -1, this);
|
||||||
|
@ -90,8 +93,8 @@ class GameState {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPurchasable (cost: { [rkey: string]: number }): boolean {
|
public isPurchasable (cost: { [rkey: string]: number } | null): boolean {
|
||||||
if (cost === null || Object.keys(cost) === null) return true;
|
if (cost === null) return true;
|
||||||
for (const rkey of Object.keys(cost)) {
|
for (const rkey of Object.keys(cost)) {
|
||||||
if (this._resources[rkey].value < cost[rkey]) {
|
if (this._resources[rkey].value < cost[rkey]) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -101,24 +104,24 @@ class GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public formatNumber (num: number): string {
|
public formatNumber (num: number): string {
|
||||||
type vlookup = { value: number, symbol: string };
|
type UnitLookup = { value: number, symbol: string };
|
||||||
const lookup: vlookup[] = [
|
const lookup: UnitLookup[] = [
|
||||||
{ value: 1, symbol: '' },
|
{ value: 1, symbol: '' },
|
||||||
{ value: 1e3, symbol: 'K' },
|
{ value: 1e3, symbol: 'K' },
|
||||||
{ value: 1e6, symbol: 'M' },
|
{ value: 1e6, symbol: 'M' },
|
||||||
{ value: 1e9, symbol: 'G' },
|
{ value: 1e9, symbol: 'G' },
|
||||||
{ value: 1e12, symbol: 'T' },
|
{ value: 1e12, symbol: 'T' },
|
||||||
{ value: 1e15, symbol: 'P' },
|
{ value: 1e15, symbol: 'P' },
|
||||||
{ value: 1e18, symbol: 'E' }
|
{ value: 1e18, symbol: 'E' },
|
||||||
];
|
];
|
||||||
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||||
let item: vlookup;
|
let item: UnitLookup | undefined;
|
||||||
for (item of lookup.slice().reverse()) {
|
for (item of lookup.slice().reverse()) {
|
||||||
if (num >= item.value) break;
|
if (num >= item.value) break;
|
||||||
}
|
}
|
||||||
return item
|
return item !== undefined
|
||||||
? (num / item.value).toFixed(this.numberFormatDigits)
|
? (num / item.value).toFixed(
|
||||||
.replace(rx, '$1') + item.symbol
|
this.numberFormatDigits).replace(rx, '$1') + item.symbol
|
||||||
: num.toFixed(this.numberFormatDigits).replace(rx, '$1');
|
: num.toFixed(this.numberFormatDigits).replace(rx, '$1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,15 +132,15 @@ class GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public save (): void {
|
public save (): void {
|
||||||
const saveObj: any = { };
|
const saveObj: SaveData = {};
|
||||||
saveObj.version = {
|
saveObj.version = {
|
||||||
maj: this._versionMaj,
|
maj: this._versionMaj,
|
||||||
min: this._versionMin
|
min: this._versionMin,
|
||||||
};
|
};
|
||||||
for (const rkey of this._resourceKeys) {
|
for (const rkey of this._resourceKeys) {
|
||||||
saveObj[rkey] = {
|
saveObj[rkey] = {
|
||||||
value: this._resources[rkey].value,
|
value: this._resources[rkey].value,
|
||||||
cost: this._resources[rkey].cost
|
cost: this._resources[rkey].cost,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const saveStr: string = btoa(JSON.stringify(saveObj));
|
const saveStr: string = btoa(JSON.stringify(saveObj));
|
||||||
|
@ -145,33 +148,32 @@ class GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public load (): void {
|
public load (): void {
|
||||||
const saveStr: string = localStorage.getItem('savegame');
|
const saveStr: string | null = localStorage.getItem('savegame');
|
||||||
if (saveStr !== null) {
|
if (saveStr !== null) {
|
||||||
try {
|
try {
|
||||||
const saveObj: { [key: string]: any } =
|
const saveObj: SaveData = <SaveData>JSON.parse(atob(saveStr));
|
||||||
JSON.parse(atob(saveStr));
|
if (this._versionMaj === saveObj.version?.maj) {
|
||||||
if (this._versionMaj === saveObj.version.maj) {
|
|
||||||
for (const rkey of this._resourceKeys) {
|
for (const rkey of this._resourceKeys) {
|
||||||
if (saveObj[rkey] !== undefined
|
const saveRes = <{
|
||||||
&& saveObj[rkey].value !== undefined
|
value: number;
|
||||||
&& saveObj[rkey].cost !== undefined) {
|
cost: { [key: string]: number } | null;
|
||||||
// @ts-ignore
|
} | undefined> saveObj[rkey];
|
||||||
this._resources[rkey].value = saveObj[rkey].value;
|
if (saveRes !== undefined) {
|
||||||
// @ts-ignore
|
// @ts-expect-error writing read-only value from save data
|
||||||
this._resources[rkey].cost = saveObj[rkey].cost;
|
this._resources[rkey].value = saveRes.value;
|
||||||
|
// @ts-expect-error writing read-only cost from save data
|
||||||
|
this._resources[rkey].cost = saveRes.cost ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// tslint:disable-next-line
|
// tslint:disable-next-line
|
||||||
console.log('The saved game is too old to load.');
|
console.log('The saved game is too old to load.');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e: unknown) {
|
||||||
// tslint:disable-next-line
|
|
||||||
console.log('There was an error loading the saved game.');
|
console.log('There was an error loading the saved game.');
|
||||||
console.log(e); // tslint:disable-line
|
console.log(e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// tslint:disable-next-line
|
|
||||||
console.log('No save game was found.');
|
console.log('No save game was found.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,3 +185,11 @@ class GameState {
|
||||||
this.log('Reset all game resources.');
|
this.log('Reset all game resources.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SaveData = {
|
||||||
|
[key: string]: {
|
||||||
|
value: number;
|
||||||
|
cost: { [key: string]: number } | null;
|
||||||
|
} | { maj: number, min: number } | undefined;
|
||||||
|
version?: { maj: number, min: number };
|
||||||
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class DebugLogger implements ILogger {
|
class DebugLogger implements ILogger {
|
||||||
private _container: HTMLElement;
|
private readonly _container: HTMLElement;
|
||||||
|
|
||||||
constructor (container: HTMLElement) {
|
constructor (container: HTMLElement) {
|
||||||
this._container = container;
|
this._container = container;
|
||||||
|
@ -9,7 +9,9 @@ class DebugLogger implements ILogger {
|
||||||
const p: HTMLElement = document.createElement('p');
|
const p: HTMLElement = document.createElement('p');
|
||||||
p.innerText = text;
|
p.innerText = text;
|
||||||
this._container.appendChild(p);
|
this._container.appendChild(p);
|
||||||
this._container.parentElement.scrollTop =
|
if (this._container.parentElement !== null) {
|
||||||
this._container.parentElement.scrollHeight;
|
this._container.parentElement.scrollTop =
|
||||||
|
this._container.parentElement.scrollHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
interface ILogger {
|
interface ILogger {
|
||||||
msg (text: string): void;
|
msg: (text: string) => void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,8 @@ class Church extends Infrastructure {
|
||||||
this._costMultiplier.money = 1.01;
|
this._costMultiplier.money = 1.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
public max (state: GameState): number {
|
public max: (state: GameState) => number = (state) =>
|
||||||
// one church per compound
|
state.getResource('cmpnd').value;
|
||||||
return state.getResource('cmpnd').value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
|
|
|
@ -5,15 +5,10 @@ class Credibility extends Passive {
|
||||||
super(
|
super(
|
||||||
'Credibility',
|
'Credibility',
|
||||||
'Affects your ability to recruit and retain followers.');
|
'Affects your ability to recruit and retain followers.');
|
||||||
this._baseMax = 100;
|
|
||||||
this.value = 100;
|
this.value = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
public max (): number {
|
public max: (state: GameState) => number = (_state) => 100;
|
||||||
return 100;
|
public inc: (state: GameState) => number = (state) =>
|
||||||
}
|
state.config.cfgCredibilityRestoreRate;
|
||||||
|
|
||||||
public inc (state: GameState): number {
|
|
||||||
return state.config.cfgCredibilityRestoreRate;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ class CryptoCurrency extends Purchasable {
|
||||||
"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.");
|
||||||
this.cost.money = 100;
|
this.cost.money = 100;
|
||||||
this._costMultiplier.money = 1.1;
|
this._costMultiplier.money = 1.1;
|
||||||
this._baseMax = 1000;
|
|
||||||
this.valueInWholeNumbers = false;
|
this.valueInWholeNumbers = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public max: (state: GameState) => number = (state) =>
|
||||||
|
state.config.cfgStartingCryptoMax;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,9 @@ class House extends Infrastructure {
|
||||||
this._costMultiplier.money = 1.01;
|
this._costMultiplier.money = 1.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
public max (state: GameState): number {
|
// two houses per compound
|
||||||
// two houses per compound
|
public max: (state: GameState) => number = (state) =>
|
||||||
return state.getResource('cmpnd').value * 2;
|
state.getResource('cmpnd').value * 2;
|
||||||
}
|
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
enum ResourceType {
|
enum ResourceType {
|
||||||
Religion = 'religion',
|
religion = 'religion',
|
||||||
Job = 'job',
|
job = 'job',
|
||||||
Consumable = 'consumable',
|
consumable = 'consumable',
|
||||||
Infrastructure = 'infrastructure',
|
infrastructure = 'infrastructure',
|
||||||
Research = 'research',
|
research = 'research',
|
||||||
Passive = 'passive'
|
passive = 'passive',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IResource {
|
interface IResource {
|
||||||
readonly resourceType: ResourceType;
|
readonly resourceType: ResourceType;
|
||||||
readonly name: string | null;
|
readonly name: string;
|
||||||
readonly description: string | null;
|
readonly description: string;
|
||||||
readonly valueInWholeNumbers: boolean;
|
readonly valueInWholeNumbers: boolean;
|
||||||
readonly clickText: string;
|
readonly clickText: string | null;
|
||||||
readonly clickDescription: string;
|
readonly clickDescription: string | null;
|
||||||
// readonly altClickText?: string;
|
// readonly altClickText?: string;
|
||||||
// readonly altClickDescription?: string;
|
// readonly altClickDescription?: string;
|
||||||
readonly value: number;
|
readonly value: number;
|
||||||
readonly cost: { [key: string]: number };
|
readonly cost: { [key: string]: number } | null;
|
||||||
|
|
||||||
max (state: GameState): number | null;
|
max: ((state: GameState) => number) | null;
|
||||||
inc (state: GameState): number | null;
|
inc: ((state: GameState) => number) | null;
|
||||||
clickAction(state: GameState): void;
|
clickAction: ((state: GameState) => void) | null;
|
||||||
// altClickAction (state: GameState): void;
|
// altClickAction (state: GameState): void;
|
||||||
addValue (amount: number, state: GameState): void;
|
addValue: (amount: number, state: GameState) => void;
|
||||||
isUnlocked (state: GameState): boolean;
|
isUnlocked: (state: GameState) => boolean;
|
||||||
advanceAction (time: number, state: GameState): void;
|
advanceAction: ((time: number, state: GameState) => void) | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/// <reference path="./Purchasable.ts" />
|
/// <reference path="./Purchasable.ts" />
|
||||||
|
|
||||||
abstract class Infrastructure extends Purchasable {
|
abstract class Infrastructure extends Purchasable {
|
||||||
public readonly resourceType: ResourceType = ResourceType.Infrastructure;
|
public readonly resourceType: ResourceType = ResourceType.infrastructure;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
/// <reference path="./IResource.ts" />
|
/// <reference path="./IResource.ts" />
|
||||||
|
|
||||||
abstract class Job implements IResource {
|
abstract class Job implements IResource {
|
||||||
public readonly resourceType: ResourceType = ResourceType.Job;
|
public readonly resourceType: ResourceType = ResourceType.job;
|
||||||
public readonly valueInWholeNumbers: boolean = true;
|
public readonly valueInWholeNumbers: boolean = true;
|
||||||
public readonly clickText: string = 'Hire';
|
public readonly clickText: string = 'Hire';
|
||||||
public readonly clickDescription: string =
|
public readonly clickDescription: string = 'Promote one of your followers.';
|
||||||
'Promote one of your followers.';
|
|
||||||
public value = 0;
|
public value = 0;
|
||||||
public readonly cost: { [key: string]: number } = { };
|
public readonly cost: { [key: string]: number } = { };
|
||||||
|
|
||||||
|
public max: ((state: GameState) => number) | null = null;
|
||||||
|
public inc: ((state: GameState) => number) | null = null;
|
||||||
|
|
||||||
protected _costMultiplier: { [key: string]: number } = { };
|
protected _costMultiplier: { [key: string]: number } = { };
|
||||||
protected _isUnlocked = false;
|
protected _isUnlocked = false;
|
||||||
|
|
||||||
|
@ -17,20 +19,14 @@ abstract class Job implements IResource {
|
||||||
public readonly description: string
|
public readonly description: string
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public max (state: GameState): number | null {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public inc (): number | null {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public clickAction (state: GameState): void {
|
public clickAction (state: GameState): void {
|
||||||
if (this._availableJobs(state) <= 0) {
|
if (this._availableJobs(state) <= 0) {
|
||||||
state.log('You have no unemployed followers to promote.');
|
state.log('You have no unemployed followers to promote.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.value < this.max(state) && state.deductCost(this.cost)) {
|
if (this.max !== null && this.value < this.max(state)
|
||||||
|
&& state.deductCost(this.cost)) {
|
||||||
this.addValue(1);
|
this.addValue(1);
|
||||||
state.log(this._hireLog(1, state));
|
state.log(this._hireLog(1, state));
|
||||||
for (const rkey of Object.keys(this._costMultiplier)) {
|
for (const rkey of Object.keys(this._costMultiplier)) {
|
||||||
|
@ -43,21 +39,21 @@ abstract class Job implements IResource {
|
||||||
this.value += amount;
|
this.value += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (_state: GameState): boolean {
|
||||||
return this._isUnlocked;
|
return this._isUnlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public advanceAction (time: number, state: GameState): void {
|
public advanceAction (_time: number, _state: GameState): void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _availableJobs (state: GameState): number {
|
protected _availableJobs (state: GameState): number {
|
||||||
// number of followers minus the number of filled jobs
|
// number of followers minus the number of filled jobs
|
||||||
const followers: number = state.getResource('plorg').value;
|
const followers: number = state.getResource('plorg').value;
|
||||||
const hired: number = state.getResources()
|
const hired: number = state.getResources().reduce(
|
||||||
.reduce((tot: number, rkey: string): number => {
|
(tot: number, rkey: string): number => {
|
||||||
const res: IResource = state.getResource(rkey);
|
const res: IResource = state.getResource(rkey);
|
||||||
return res.resourceType === ResourceType.Job
|
return res.resourceType === ResourceType.job
|
||||||
? tot + res.value
|
? tot + res.value
|
||||||
: tot;
|
: tot;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -66,7 +62,7 @@ abstract class Job implements IResource {
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _hireLog (amount: number, state: GameState): string {
|
protected _hireLog (amount: number, _state: GameState): string {
|
||||||
return `You hired ${amount} x ${this.name}.`;
|
return `You hired ${amount} x ${this.name}.`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,11 @@ class MegaChurch extends Infrastructure {
|
||||||
'Room for 5 pastors');
|
'Room for 5 pastors');
|
||||||
this.cost.money = 7500000;
|
this.cost.money = 7500000;
|
||||||
this._costMultiplier.money = 1.01;
|
this._costMultiplier.money = 1.01;
|
||||||
this._baseMax = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public max: (state: GameState) => number = (state) =>
|
||||||
|
state.config.cfgStartingMegaChurchMax;
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
const permit: IResource = state.getResource('blpmt');
|
const permit: IResource = state.getResource('blpmt');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/// <reference path="./Purchasable.ts" />
|
/// <reference path="./Purchasable.ts" />
|
||||||
|
|
||||||
class Money extends Purchasable {
|
class Money extends Purchasable {
|
||||||
public readonly resourceType: ResourceType = ResourceType.Consumable;
|
public readonly resourceType: ResourceType = ResourceType.consumable;
|
||||||
|
|
||||||
private _lastCollectionTime = 0;
|
private _lastCollectionTime = 0;
|
||||||
|
|
||||||
|
@ -11,18 +11,17 @@ class Money extends Purchasable {
|
||||||
super('Money', 'Used to purchase goods and services.');
|
super('Money', 'Used to purchase goods and services.');
|
||||||
this.clickText = 'Collect Tithes';
|
this.clickText = 'Collect Tithes';
|
||||||
this.clickDescription = 'Voluntary contributions from followers.';
|
this.clickDescription = 'Voluntary contributions from followers.';
|
||||||
this._baseMax = 500000;
|
|
||||||
this.valueInWholeNumbers = false;
|
this.valueInWholeNumbers = false;
|
||||||
this._isUnlocked = true;
|
this._isUnlocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public max (state: GameState): number | null {
|
public max: (state: GameState) => number = (state: GameState) => {
|
||||||
let max: number = this._baseMax;
|
let max: number = state.config.cfgStartingMoneyMax;
|
||||||
max += state.getResource('cmpnd').value * 500000;
|
max += state.getResource('cmpnd').value * 500000;
|
||||||
return max;
|
return max;
|
||||||
}
|
};
|
||||||
|
|
||||||
public inc (state: GameState): number {
|
public inc: (state: GameState) => number = (state) => {
|
||||||
let inc = 0;
|
let inc = 0;
|
||||||
|
|
||||||
// crypto currency
|
// crypto currency
|
||||||
|
@ -30,7 +29,7 @@ class Money extends Purchasable {
|
||||||
* state.config.cfgCryptoReturnAmount;
|
* state.config.cfgCryptoReturnAmount;
|
||||||
|
|
||||||
return inc;
|
return inc;
|
||||||
}
|
};
|
||||||
|
|
||||||
protected _purchaseAmount (state: GameState): number {
|
protected _purchaseAmount (state: GameState): number {
|
||||||
const plorg: IResource = state.getResource('plorg');
|
const plorg: IResource = state.getResource('plorg');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/// <reference path="./IResource.ts" />
|
/// <reference path="./IResource.ts" />
|
||||||
|
|
||||||
abstract class Passive implements IResource {
|
abstract class Passive implements IResource {
|
||||||
public readonly resourceType: ResourceType = ResourceType.Passive;
|
public readonly resourceType: ResourceType = ResourceType.passive;
|
||||||
public readonly valueInWholeNumbers: boolean = false;
|
public readonly valueInWholeNumbers: boolean = false;
|
||||||
public readonly clickText: null = null;
|
public readonly clickText: null = null;
|
||||||
public readonly clickDescription: null = null;
|
public readonly clickDescription: null = null;
|
||||||
|
@ -10,31 +10,22 @@ abstract class Passive implements IResource {
|
||||||
|
|
||||||
public readonly clickAction: null = null;
|
public readonly clickAction: null = null;
|
||||||
|
|
||||||
protected _baseMax: number | null;
|
public max: ((state: GameState) => number) | null = null;
|
||||||
protected _baseInc: number | null;
|
public inc: ((state: GameState) => number) | null = null;
|
||||||
|
public advanceAction: ((time: number, state: GameState) => void) | null = null;
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
public readonly name: string,
|
public readonly name: string,
|
||||||
public readonly description: string
|
public readonly description: string
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public max (state: GameState): number | null {
|
|
||||||
return this._baseMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public inc (state: GameState): number | null {
|
public addValue (amount: number, _state: GameState): void {
|
||||||
return this._baseInc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addValue (amount: number, state: GameState): void {
|
|
||||||
this.value += amount;
|
this.value += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (_state: GameState): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public advanceAction (time: number, state: GameState): void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@ class Pastor extends Job {
|
||||||
'Collect tithings for you and recruit new members from other faiths automatically.');
|
'Collect tithings for you and recruit new members from other faiths automatically.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public max (state: GameState): number {
|
public max: (state: GameState) => number = (state) => {
|
||||||
let max: number = state.getResource('chrch').value * 2;
|
let max: number = state.getResource('chrch').value * 2;
|
||||||
max += state.getResource('mchch').value * 5;
|
max += state.getResource('mchch').value * 5;
|
||||||
return max;
|
return max;
|
||||||
}
|
};
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (state: GameState): boolean {
|
||||||
if (this._isUnlocked) return true;
|
if (this._isUnlocked) return true;
|
||||||
|
@ -30,7 +30,7 @@ class Pastor extends Job {
|
||||||
if (Math.floor(plorg.value) < tithed)
|
if (Math.floor(plorg.value) < tithed)
|
||||||
tithed = Math.floor(plorg.value);
|
tithed = Math.floor(plorg.value);
|
||||||
let collected: number = tithed * state.config.cfgTitheAmount;
|
let collected: number = tithed * state.config.cfgTitheAmount;
|
||||||
if (collected > money.max(state) - money.value)
|
if (money.max !== null && collected > money.max(state) - money.value)
|
||||||
collected = money.max(state) - money.value;
|
collected = money.max(state) - money.value;
|
||||||
if (collected > 0) {
|
if (collected > 0) {
|
||||||
money.addValue(collected, state);
|
money.addValue(collected, state);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/// <reference path="./IResource.ts" />
|
/// <reference path="./IResource.ts" />
|
||||||
|
|
||||||
class PlayerOrg implements IResource {
|
class PlayerOrg implements IResource {
|
||||||
public readonly resourceType: ResourceType = ResourceType.Religion;
|
public readonly resourceType: ResourceType = ResourceType.religion;
|
||||||
public readonly name: string = 'Player';
|
public readonly name: string = 'Player';
|
||||||
public readonly description: string = 'In you they trust.';
|
public readonly description: string = 'In you they trust.';
|
||||||
public readonly valueInWholeNumbers: boolean = true;
|
public readonly valueInWholeNumbers: boolean = true;
|
||||||
|
@ -11,13 +11,12 @@ class PlayerOrg implements IResource {
|
||||||
public readonly cost: null = null;
|
public readonly cost: null = null;
|
||||||
|
|
||||||
private _timeSinceLastLost = 0;
|
private _timeSinceLastLost = 0;
|
||||||
private _baseMax = 5;
|
|
||||||
private _lastRecruitmentLog = 0;
|
private _lastRecruitmentLog = 0;
|
||||||
private _followerSources: { [key: string]: number } = { };
|
private _followerSources: { [key: string]: number } = { };
|
||||||
private _followerDests: { [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 = state.config.cfgStartingPlayerMax;
|
||||||
max += state.getResource('tents').value * 2;
|
max += state.getResource('tents').value * 2;
|
||||||
max += state.getResource('house').value * 10;
|
max += state.getResource('house').value * 10;
|
||||||
return max;
|
return max;
|
||||||
|
@ -27,12 +26,12 @@ class PlayerOrg implements IResource {
|
||||||
let inc = 0;
|
let inc = 0;
|
||||||
|
|
||||||
// pastor recruiting
|
// pastor recruiting
|
||||||
const pastors: number = state.getResource('pstor').value;
|
const pastors = state.getResource('pstor').value;
|
||||||
inc += pastors * state.config.cfgPastorRecruitRate;
|
inc += pastors * state.config.cfgPastorRecruitRate;
|
||||||
|
|
||||||
// credibility adjustment
|
// credibility adjustment
|
||||||
const creds: IResource = state.getResource('creds');
|
const creds = state.getResource('creds');
|
||||||
inc *= creds.value / creds.max(state);
|
if (creds.max !== null) inc *= creds.value / creds.max(state);
|
||||||
|
|
||||||
return inc;
|
return inc;
|
||||||
}
|
}
|
||||||
|
@ -46,10 +45,12 @@ class PlayerOrg implements IResource {
|
||||||
|
|
||||||
// chance to fail increases as credibility decreases
|
// chance to fail increases as credibility decreases
|
||||||
const creds: IResource = state.getResource('creds');
|
const creds: IResource = state.getResource('creds');
|
||||||
const ratio: number = Math.ceil(creds.value) / creds.max(state);
|
if (creds.max !== null) {
|
||||||
if (Math.random() > ratio) {
|
const ratio: number = Math.ceil(creds.value) / creds.max(state);
|
||||||
state.log('Your recruitment efforts failed.');
|
if (Math.random() > ratio) {
|
||||||
return;
|
state.log('Your recruitment efforts failed.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._lastRecruitmentLog = 0; // always log on click
|
this._lastRecruitmentLog = 0; // always log on click
|
||||||
|
@ -57,17 +58,17 @@ class PlayerOrg implements IResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
public addValue (amount: number, state: GameState): void {
|
public addValue (amount: number, state: GameState): void {
|
||||||
const oldValue: number = this.value;
|
const oldValue = this.value;
|
||||||
this.value += amount;
|
this.value += amount;
|
||||||
const diff: number = Math.floor(this.value) - Math.floor(oldValue);
|
const diff = Math.floor(this.value) - Math.floor(oldValue);
|
||||||
|
|
||||||
if (diff > 0) {
|
if (diff > 0) {
|
||||||
// gained followers must come from other faiths
|
// gained followers must come from other faiths
|
||||||
for (let i = 0; i < diff; i++) {
|
for (let i = 0; i < diff; i++) {
|
||||||
const source: [string, IResource] = this._getRandomReligion(state);
|
const source = this._getRandomReligion(state);
|
||||||
source[1].addValue(-1, state);
|
source[1].addValue(-1, state);
|
||||||
const curFollowers: number = this._followerSources[source[0]];
|
const curFollowers = this._followerSources[source[0]];
|
||||||
this._followerSources[source[0]] = curFollowers
|
this._followerSources[source[0]] = !isNaN(curFollowers)
|
||||||
? curFollowers + 1
|
? curFollowers + 1
|
||||||
: 1;
|
: 1;
|
||||||
}
|
}
|
||||||
|
@ -77,14 +78,14 @@ class PlayerOrg implements IResource {
|
||||||
const dest: [string, IResource] = this._getRandomReligion(state);
|
const dest: [string, IResource] = this._getRandomReligion(state);
|
||||||
dest[1].addValue(1, state);
|
dest[1].addValue(1, state);
|
||||||
const curFollowers: number = this._followerDests[dest[0]];
|
const curFollowers: number = this._followerDests[dest[0]];
|
||||||
this._followerDests[dest[0]] = curFollowers
|
this._followerDests[dest[0]] = !isNaN(curFollowers)
|
||||||
? curFollowers + 1
|
? curFollowers + 1
|
||||||
: 1;
|
: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (_state: GameState): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,11 +94,13 @@ class PlayerOrg implements IResource {
|
||||||
this._timeSinceLastLost += time;
|
this._timeSinceLastLost += time;
|
||||||
if (this._timeSinceLastLost > 10000) {
|
if (this._timeSinceLastLost > 10000) {
|
||||||
if (this.value > 0) {
|
if (this.value > 0) {
|
||||||
const creds: IResource = state.getResource('creds');
|
const creds = state.getResource('creds');
|
||||||
const ratio: number = Math.ceil(creds.value) / creds.max(state);
|
if (creds.max !== null) {
|
||||||
if (Math.random() > ratio) {
|
const ratio: number = Math.ceil(creds.value) / creds.max(state);
|
||||||
const lost: number = Math.ceil(this.value / 25 * (1 - ratio));
|
if (Math.random() > ratio) {
|
||||||
this.addValue(lost * -1, state);
|
const lost: number = Math.ceil(this.value / 25 * (1 - ratio));
|
||||||
|
this.addValue(lost * -1, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._timeSinceLastLost = 0;
|
this._timeSinceLastLost = 0;
|
||||||
|
@ -113,8 +116,7 @@ class PlayerOrg implements IResource {
|
||||||
for (const rkey of Object.keys(this._followerDests)) {
|
for (const rkey of Object.keys(this._followerDests)) {
|
||||||
if (msg !== '') msg += ', ';
|
if (msg !== '') msg += ', ';
|
||||||
const religion: IResource = state.getResource(rkey);
|
const religion: IResource = state.getResource(rkey);
|
||||||
msg +=
|
msg += `${state.formatNumber(this._followerDests[rkey])} to ${religion.name}`;
|
||||||
`${state.formatNumber(this._followerDests[rkey])} to ${religion.name}`;
|
|
||||||
total += this._followerDests[rkey];
|
total += this._followerDests[rkey];
|
||||||
delete this._followerDests[rkey];
|
delete this._followerDests[rkey];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
/// <reference path="./IResource.ts" />
|
/// <reference path="./IResource.ts" />
|
||||||
|
|
||||||
abstract class Purchasable implements IResource {
|
abstract class Purchasable implements IResource {
|
||||||
public readonly resourceType: ResourceType = ResourceType.Consumable;
|
public readonly resourceType: ResourceType = ResourceType.consumable;
|
||||||
public valueInWholeNumbers = true;
|
public valueInWholeNumbers = true;
|
||||||
public clickText = 'Purchase';
|
public clickText = 'Purchase';
|
||||||
public clickDescription = 'Purchase';
|
public clickDescription = 'Purchase';
|
||||||
public value = 0;
|
public value = 0;
|
||||||
public readonly cost: { [key: string]: number } = { };
|
public readonly cost: { [key: string]: number } = { };
|
||||||
|
|
||||||
|
public inc: ((state: GameState) => number) | null = null;
|
||||||
|
public max: ((_state: GameState) => number) | null = null;
|
||||||
|
|
||||||
protected _costMultiplier: { [key: string]: number } = { };
|
protected _costMultiplier: { [key: string]: number } = { };
|
||||||
protected _baseMax: number | null = null;
|
|
||||||
protected _isUnlocked = false;
|
protected _isUnlocked = false;
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
@ -17,16 +19,9 @@ abstract class Purchasable implements IResource {
|
||||||
public readonly description: string
|
public readonly description: string
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public max (state: GameState): number | null {
|
|
||||||
return this._baseMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public inc (state: GameState): number | null {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public clickAction (state: GameState): void {
|
public clickAction (state: GameState): void {
|
||||||
if (this.max(state) !== null && this.value >= this.max(state)) return;
|
if (this.max !== null && this.value >= this.max(state)) return;
|
||||||
if (state.deductCost(this.cost)) {
|
if (state.deductCost(this.cost)) {
|
||||||
const amount: number = this._purchaseAmount(state);
|
const amount: number = this._purchaseAmount(state);
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
|
@ -39,7 +34,7 @@ abstract class Purchasable implements IResource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public addValue (amount: number, state: GameState): void {
|
public addValue (amount: number, _state: GameState): void {
|
||||||
this.value += amount;
|
this.value += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/// <reference path="./IResource.ts" />
|
/// <reference path="./IResource.ts" />
|
||||||
|
|
||||||
class Religion implements IResource {
|
class Religion implements IResource {
|
||||||
public readonly resourceType: ResourceType = ResourceType.Religion;
|
public readonly resourceType: ResourceType = ResourceType.religion;
|
||||||
public readonly valueInWholeNumbers: boolean = true;
|
public readonly valueInWholeNumbers: boolean = true;
|
||||||
public readonly clickText: null = null;
|
public readonly clickText: null = null;
|
||||||
public readonly clickDescription: null = null;
|
public readonly clickDescription: null = null;
|
||||||
|
@ -18,11 +18,11 @@ class Religion implements IResource {
|
||||||
public value: number,
|
public value: number,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public addValue (amount: number, state: GameState): void {
|
public addValue (amount: number, _state: GameState): void {
|
||||||
this.value += amount;
|
this.value += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isUnlocked (state: GameState): boolean {
|
public isUnlocked (_state: GameState): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/// <reference path="./Purchasable.ts" />
|
/// <reference path="./Purchasable.ts" />
|
||||||
|
|
||||||
abstract class Research extends Purchasable {
|
abstract class Research extends Purchasable {
|
||||||
public readonly resourceType: ResourceType = ResourceType.Research;
|
public readonly resourceType: ResourceType = ResourceType.research;
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
public readonly name: string,
|
public readonly name: string,
|
||||||
|
@ -9,8 +9,9 @@ abstract class Research extends Purchasable {
|
||||||
) {
|
) {
|
||||||
super(name, description);
|
super(name, description);
|
||||||
this.value = 0;
|
this.value = 0;
|
||||||
this._baseMax = 1;
|
|
||||||
this.clickText = 'Learn';
|
this.clickText = 'Learn';
|
||||||
this.clickDescription = 'Complete this research.'
|
this.clickDescription = 'Complete this research.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public max: (_state: GameState) => number = (_state) => 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,12 @@ class Tent extends Infrastructure {
|
||||||
'Provides room to house 2 followers.');
|
'Provides room to house 2 followers.');
|
||||||
this.cost.money = 250;
|
this.cost.money = 250;
|
||||||
this._costMultiplier.money = 1.05;
|
this._costMultiplier.money = 1.05;
|
||||||
this._baseMax = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public max (state: GameState): number {
|
public max: (state: GameState) => number = (state) => {
|
||||||
// ten extra tents per compound
|
// ten extra tents per compound
|
||||||
let max: number = this._baseMax;
|
let max: number = state.config.cfgStartingTentMax;
|
||||||
max += state.getResource('cmpnd').value * 10;
|
max += state.getResource('cmpnd').value * 10;
|
||||||
return max;
|
return max;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,41 @@
|
||||||
/// <reference path="../model/logging/DebugLogger.ts" />
|
/// <reference path="../model/logging/DebugLogger.ts" />
|
||||||
|
|
||||||
class DebugRenderer implements IRenderer { // eslint-disable-line @typescript-eslint/no-unused-vars
|
class DebugRenderer implements IRenderer {
|
||||||
private _initialized = false;
|
private _initialized = false;
|
||||||
private _handleClick = true;
|
private _handleClick = true;
|
||||||
|
|
||||||
public render (state: GameState): void {
|
public render (state: GameState): void {
|
||||||
const rkeys: string[] = state.getResources();
|
const rkeys: string[] = state.getResources();
|
||||||
|
const container = document.getElementById('irreligious-game');
|
||||||
if (!this._initialized) {
|
if (!this._initialized) {
|
||||||
const container: HTMLElement =
|
if (container === null) {
|
||||||
document.getElementById('irreligious-game');
|
console.error('could not find game container');
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._initialized = true;
|
this._initialized = true;
|
||||||
state.onResourceClick.push((): void => {
|
state.onResourceClick.push((): void => {
|
||||||
this._handleClick = true;
|
this._handleClick = true;
|
||||||
});
|
});
|
||||||
const style: HTMLElement = document.createElement('link');
|
const style = document.createElement('link');
|
||||||
style.setAttribute('rel', 'stylesheet');
|
style.setAttribute('rel', 'stylesheet');
|
||||||
style.setAttribute('href', 'css/debugger.css');
|
style.setAttribute('href', 'css/debugger.css');
|
||||||
const head: HTMLElement = document.getElementsByTagName('head')[0];
|
const head = document.getElementsByTagName('head')[0];
|
||||||
head.appendChild(style);
|
head.appendChild(style);
|
||||||
// create resource area and logging area
|
// create resource area and logging area
|
||||||
const resDiv: HTMLElement = document.createElement('div');
|
const resDiv = document.createElement('div');
|
||||||
resDiv.id = 'resource-section';
|
resDiv.id = 'resource-section';
|
||||||
container.appendChild(resDiv);
|
container.appendChild(resDiv);
|
||||||
const logDiv: HTMLElement = document.createElement('div');
|
const logDiv = document.createElement('div');
|
||||||
logDiv.id = 'logging-section';
|
logDiv.id = 'logging-section';
|
||||||
container.appendChild(logDiv);
|
container.appendChild(logDiv);
|
||||||
const logContent: HTMLElement = document.createElement('div');
|
const logContent = document.createElement('div');
|
||||||
logDiv.appendChild(logContent);
|
logDiv.appendChild(logContent);
|
||||||
state.logger = new DebugLogger(logContent);
|
state.logger = new DebugLogger(logContent);
|
||||||
// create containers for each resource type
|
// create containers for each resource type
|
||||||
for (const item in ResourceType) {
|
for (const item in ResourceType) {
|
||||||
if (isNaN(Number(item))) {
|
if (isNaN(Number(item))) {
|
||||||
const el: HTMLElement = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.id = `resource-container-${<string>ResourceType[item]}`;
|
el.id = `resource-container-${item.toString()}`;
|
||||||
el.className = 'resource-type-container';
|
el.className = 'resource-type-container';
|
||||||
resDiv.appendChild(el);
|
resDiv.appendChild(el);
|
||||||
}
|
}
|
||||||
|
@ -40,23 +43,21 @@ class DebugRenderer implements IRenderer { // eslint-disable-line @typescript-es
|
||||||
// create containers for each resource
|
// create containers for each resource
|
||||||
for (const rkey of rkeys) {
|
for (const rkey of rkeys) {
|
||||||
const resource: IResource = state.getResource(rkey);
|
const resource: IResource = state.getResource(rkey);
|
||||||
const resContainer: HTMLElement =
|
const resContainer = document.getElementById(
|
||||||
document.getElementById(
|
`resource-container-${resource.resourceType}`);
|
||||||
`resource-container-${resource.resourceType}`);
|
if (resContainer === null) continue;
|
||||||
const el: HTMLElement = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.className = 'resource locked';
|
el.className = 'resource locked';
|
||||||
el.id = `resource-details-${rkey}`;
|
el.id = `resource-details-${rkey}`;
|
||||||
let content = `
|
let content = `
|
||||||
<span class='resource-title'
|
<span class='resource-title'
|
||||||
title='${this._escape(resource.description)}'>
|
title='${this._escape(resource.description)}'>
|
||||||
${this._escape(resource.name
|
${this._escape(resource.name)}</span><br>
|
||||||
? resource.name
|
|
||||||
: rkey)}</span><br>
|
|
||||||
<span class='resource-value'></span>
|
<span class='resource-value'></span>
|
||||||
<span class='resource-max'></span>
|
<span class='resource-max'></span>
|
||||||
<span class='resource-inc'></span>
|
<span class='resource-inc'></span>
|
||||||
`;
|
`;
|
||||||
if (resource.clickText !== null) {
|
if (resource.clickText !== null && resource.clickDescription !== null) {
|
||||||
content += `<br>
|
content += `<br>
|
||||||
<button class='resource-btn'
|
<button class='resource-btn'
|
||||||
title='${this._escape(resource.clickDescription)}'>
|
title='${this._escape(resource.clickDescription)}'>
|
||||||
|
@ -71,31 +72,29 @@ class DebugRenderer implements IRenderer { // eslint-disable-line @typescript-es
|
||||||
if (resource.clickAction !== null) {
|
if (resource.clickAction !== null) {
|
||||||
const btn: Element =
|
const btn: Element =
|
||||||
el.getElementsByClassName('resource-btn')[0];
|
el.getElementsByClassName('resource-btn')[0];
|
||||||
btn.addEventListener('click', (): void =>
|
btn.addEventListener('click', (): void => {
|
||||||
state.performClick(rkey));
|
state.performClick(rkey);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create tools footer
|
// create tools footer
|
||||||
const footer: HTMLElement = document.createElement('div');
|
const footer = document.createElement('div');
|
||||||
footer.className = 'footer';
|
footer.className = 'footer';
|
||||||
footer.innerHTML = `
|
footer.innerHTML = `
|
||||||
<button id='dbg-btn-reset'>Reset Game</button>
|
<button id='dbg-btn-reset'>Reset Game</button>
|
||||||
`;
|
`;
|
||||||
resDiv.appendChild(footer);
|
resDiv.appendChild(footer);
|
||||||
document.getElementById('dbg-btn-reset')
|
document.getElementById('dbg-btn-reset')?.addEventListener('click',
|
||||||
.addEventListener('click', (): void => {
|
(): void => {
|
||||||
state.reset();
|
state.reset();
|
||||||
document.getElementById('irreligious-game').innerHTML = '';
|
container.innerHTML = '';
|
||||||
this._initialized = false;
|
this._initialized = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
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 el = document.getElementById(`resource-details-${rkey}`);
|
||||||
.getElementById(`resource-container-${resource.resourceType}`);
|
if (el !== null && resource.isUnlocked(state)) {
|
||||||
const el: HTMLElement = document
|
|
||||||
.getElementById(`resource-details-${rkey}`);
|
|
||||||
if (resource.isUnlocked(state)) {
|
|
||||||
if (el.className !== 'resource') el.className = 'resource';
|
if (el.className !== 'resource') el.className = 'resource';
|
||||||
const elV: Element =
|
const elV: Element =
|
||||||
el.getElementsByClassName('resource-value')[0];
|
el.getElementsByClassName('resource-value')[0];
|
||||||
|
@ -106,15 +105,13 @@ class DebugRenderer implements IRenderer { // eslint-disable-line @typescript-es
|
||||||
: resource.value;
|
: resource.value;
|
||||||
elV.innerHTML = state.formatNumber(value);
|
elV.innerHTML = state.formatNumber(value);
|
||||||
elT.innerHTML = resource.max !== null
|
elT.innerHTML = resource.max !== null
|
||||||
&& resource.max(state) !== null
|
|
||||||
? ` / ${state.formatNumber(resource.max(state))}`
|
? ` / ${state.formatNumber(resource.max(state))}`
|
||||||
: '';
|
: '';
|
||||||
const elB: HTMLCollectionOf<Element> =
|
const elB: HTMLCollectionOf<Element> =
|
||||||
el.getElementsByClassName('resource-btn');
|
el.getElementsByClassName('resource-btn');
|
||||||
if (elB.length > 0) {
|
if (elB.length > 0) {
|
||||||
const enabled: boolean = state.isPurchasable(resource.cost)
|
const enabled: boolean = state.isPurchasable(resource.cost)
|
||||||
&& (resource.max(state) === null
|
&& (resource.max === null || resource.value < resource.max(state));
|
||||||
|| resource.value < resource.max(state));
|
|
||||||
if (enabled) elB[0].removeAttribute('disabled');
|
if (enabled) elB[0].removeAttribute('disabled');
|
||||||
else elB[0].setAttribute('disabled', 'disabled');
|
else elB[0].setAttribute('disabled', 'disabled');
|
||||||
}
|
}
|
||||||
|
@ -132,7 +129,7 @@ class DebugRenderer implements IRenderer { // eslint-disable-line @typescript-es
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (el.className !== 'resource locked')
|
if (el !== null && el.className !== 'resource locked')
|
||||||
el.className = 'resource locked';
|
el.className = 'resource locked';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,8 +143,8 @@ class DebugRenderer implements IRenderer { // eslint-disable-line @typescript-es
|
||||||
'>': '>',
|
'>': '>',
|
||||||
'"': '"',
|
'"': '"',
|
||||||
"'": ''',
|
"'": ''',
|
||||||
'/': '/'
|
'/': '/',
|
||||||
}
|
};
|
||||||
const escaper = /[&<>"'/]/g;
|
const escaper = /[&<>"'/]/g;
|
||||||
return text.replace(escaper, (match: string): string =>
|
return text.replace(escaper, (match: string): string =>
|
||||||
escapes[match]);
|
escapes[match]);
|
||||||
|
@ -155,8 +152,9 @@ class DebugRenderer implements IRenderer { // eslint-disable-line @typescript-es
|
||||||
|
|
||||||
private _getCostStr (resource: IResource, state: GameState): string {
|
private _getCostStr (resource: IResource, state: GameState): string {
|
||||||
let cost = '';
|
let cost = '';
|
||||||
for (const rkey of state.getResources()) {
|
if (resource.cost !== null) {
|
||||||
if (resource.cost[rkey] !== undefined) {
|
for (const rkey of state.getResources()) {
|
||||||
|
if (isNaN(resource.cost[rkey])) continue;
|
||||||
if (cost !== '') cost += ', ';
|
if (cost !== '') cost += ', ';
|
||||||
if (rkey === 'money') {
|
if (rkey === 'money') {
|
||||||
cost += `$${state.formatNumber(resource.cost[rkey])}`;
|
cost += `$${state.formatNumber(resource.cost[rkey])}`;
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
interface IRenderer { // eslint-disable-line @typescript-eslint/no-unused-vars
|
interface IRenderer {
|
||||||
render (state: GameState): void;
|
render: (state: GameState) => void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"noImplicitAny": false,
|
|
||||||
"rootDir": "./src/",
|
"rootDir": "./src/",
|
||||||
"outFile": "./public/js/irreligious.js",
|
"outFile": "./public/js/irreligious.js",
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictPropertyInitialization": true,
|
||||||
"target": "ES5",
|
"target": "ES5",
|
||||||
"module": "none",
|
"module": "none",
|
||||||
"plugins": [{"name": "typescript-eslint-language-service"}]
|
"plugins": [{"name": "typescript-eslint-language-service"}]
|
||||||
|
|
Reference in New Issue