diff --git a/public/css/debugger.css b/public/css/debugger.css
index 8713844..cb6f982 100644
--- a/public/css/debugger.css
+++ b/public/css/debugger.css
@@ -52,7 +52,7 @@ body, html {
#resource-container-job .resource {
background-color: #fcf;
}
-#resource-container-consumable .resource {
+#resource-container-purchasable .resource {
background-color: #cfc;
}
#resource-container-infrastructure .resource {
diff --git a/src/model/GameConfig.ts b/src/model/GameConfig.ts
index 15d218b..b680fbe 100644
--- a/src/model/GameConfig.ts
+++ b/src/model/GameConfig.ts
@@ -105,12 +105,12 @@ class GameConfig {
const state = new GameState(this);
// create player organization
- state.addResource(ResourceKey.followers, new Follower());
+ state.addResource(new Follower());
// create world religions
state.addResource(
- ResourceKey.christianity,
new Religion(
+ ResourceKey.christianity,
'Christianity',
'christian',
'christians',
@@ -120,8 +120,8 @@ class GameConfig {
);
state.addResource(
- ResourceKey.islam,
new Religion(
+ ResourceKey.islam,
'Islam',
'muslim',
'muslims',
@@ -131,8 +131,8 @@ class GameConfig {
);
state.addResource(
- ResourceKey.hinduism,
new Religion(
+ ResourceKey.hinduism,
'Hinduism',
'hindu',
'hindus',
@@ -142,8 +142,8 @@ class GameConfig {
);
state.addResource(
- ResourceKey.buddhism,
new Religion(
+ ResourceKey.buddhism,
'Buddhism',
'buddhist',
'buddhists',
@@ -153,8 +153,8 @@ class GameConfig {
);
state.addResource(
- ResourceKey.sikhism,
new Religion(
+ ResourceKey.sikhism,
'Sikhism',
'sikh',
'sikhs',
@@ -164,8 +164,8 @@ class GameConfig {
);
state.addResource(
- ResourceKey.judaism,
new Religion(
+ ResourceKey.judaism,
'Judaism',
'jew',
'jews',
@@ -175,8 +175,8 @@ class GameConfig {
);
state.addResource(
- ResourceKey.other,
new Religion(
+ ResourceKey.other,
'Other',
'person from other faiths',
'people from other faiths',
@@ -186,8 +186,8 @@ class GameConfig {
);
state.addResource(
- ResourceKey.atheism,
new Religion(
+ ResourceKey.atheism,
'Non-Religious',
'atheist',
'atheists',
@@ -197,24 +197,24 @@ class GameConfig {
);
// add jobs
- state.addResource(ResourceKey.pastors, new Pastor());
- state.addResource(ResourceKey.compoundManagers, new CompoundManager());
+ state.addResource(new Pastor());
+ state.addResource(new CompoundManager());
// add resources
- state.addResource(ResourceKey.money, new Money(3.5));
- state.addResource(ResourceKey.cryptoCurrency, new CryptoCurrency(this));
- state.addResource(ResourceKey.tents, new Tent(this));
- state.addResource(ResourceKey.houses, new House(this));
- state.addResource(ResourceKey.churches, new Church(this));
- state.addResource(ResourceKey.compounds, new Compound(this));
- state.addResource(ResourceKey.megaChurches, new Megachurch(this));
+ state.addResource(new Money(3.5));
+ state.addResource(new CryptoCurrency(this));
+ state.addResource(new Tent(this));
+ state.addResource(new House(this));
+ state.addResource(new Church(this));
+ state.addResource(new Compound(this));
+ state.addResource(new Megachurch(this));
// add research
- state.addResource(ResourceKey.buildingPermit, new BuildingPermit(this));
+ state.addResource(new BuildingPermit(this));
// add passive resources
- state.addResource(ResourceKey.credibility, new Credibility(this));
- state.addResource(ResourceKey.cryptoMarket, new CryptoMarket(this));
+ state.addResource(new Credibility(this));
+ state.addResource(new CryptoMarket(this));
return state;
}
diff --git a/src/model/GameState.ts b/src/model/GameState.ts
index 2f063f5..e32c23e 100644
--- a/src/model/GameState.ts
+++ b/src/model/GameState.ts
@@ -26,9 +26,9 @@ class GameState {
return this._resourceKeys;
}
- public addResource(key: ResourceKey, resource: IResource): void {
- this._resourceKeys.push(key);
- this._resources[key] = resource;
+ public addResource(resource: IResource): void {
+ this._resourceKeys.push(resource.resourceKey);
+ this._resources[resource.resourceKey] = resource;
}
public advance(time: number): void {
@@ -161,16 +161,7 @@ class GameState {
if (resource === undefined) continue;
const saveRes = saveObj.resources[rkey];
if (saveRes !== undefined) {
- // @ts-expect-error writing read-only value from save data
- resource.value = saveRes.value;
- // @ts-expect-error writing read-only cost from save data
- resource.cost = saveRes.cost;
- if (
- saveRes.config !== undefined &&
- resource.restoreConfig !== undefined
- ) {
- resource.restoreConfig(saveRes.config);
- }
+ resource.restoreConfig(saveRes);
}
}
} else {
diff --git a/src/model/resource/BuildingPermit.ts b/src/model/resource/BuildingPermit.ts
index 620cf42..7061471 100644
--- a/src/model/resource/BuildingPermit.ts
+++ b/src/model/resource/BuildingPermit.ts
@@ -1,6 +1,8 @@
///
class BuildingPermit extends Research {
+ public readonly resourceKey = ResourceKey.buildingPermit;
+
constructor(config: GameConfig) {
super(
'Building Permit',
@@ -11,12 +13,12 @@ class BuildingPermit extends Research {
this.cost.money = config.cfgInitialCost.buildingPermit;
}
- public isUnlocked(state: GameState): boolean {
+ public isUnlocked = (state: GameState): boolean => {
if (this._isUnlocked) return true;
const compounds = state.resource.compounds;
if (compounds !== undefined && compounds.value > 0) {
this._isUnlocked = true;
}
return this._isUnlocked;
- }
+ };
}
diff --git a/src/model/resource/Church.ts b/src/model/resource/Church.ts
index a7c0cc6..0fa2470 100644
--- a/src/model/resource/Church.ts
+++ b/src/model/resource/Church.ts
@@ -1,6 +1,8 @@
///
class Church extends Infrastructure {
+ public readonly resourceKey = ResourceKey.churches;
+
constructor(config: GameConfig) {
super(
'Churches',
@@ -17,13 +19,11 @@ class Church extends Infrastructure {
this._costMultiplier.money = config.cfgCostMultiplier.churches;
}
- public max: (state: GameState) => number = (state) =>
- Math.floor(
- (state.resource.compounds?.value ?? 0) *
- (state.config.cfgCapacity.compounds?.churches ?? 0)
- );
+ public max = (state: GameState): number =>
+ (state.resource.compounds?.value ?? 0) *
+ (state.config.cfgCapacity.compounds?.churches ?? 0);
- public inc: (state: GameState) => number = (state) => {
+ public inc = (state: GameState): number => {
// compound managers
return (
(state.resource.compoundManagers?.value ?? 0) *
@@ -31,12 +31,12 @@ class Church extends Infrastructure {
);
};
- public isUnlocked(state: GameState): boolean {
+ public isUnlocked = (state: GameState): boolean => {
if (this._isUnlocked) return true;
const compounds = state.resource.compounds;
if (compounds !== undefined && compounds.value > 0) {
this._isUnlocked = true;
}
return this._isUnlocked;
- }
+ };
}
diff --git a/src/model/resource/Compound.ts b/src/model/resource/Compound.ts
index 27382ff..e3bd02d 100644
--- a/src/model/resource/Compound.ts
+++ b/src/model/resource/Compound.ts
@@ -1,6 +1,8 @@
///
class Compound extends Infrastructure {
+ public readonly resourceKey = ResourceKey.compounds;
+
constructor(config: GameConfig) {
super(
'Compounds',
@@ -13,7 +15,7 @@ class Compound extends Infrastructure {
this._costMultiplier.money = config.cfgCostMultiplier.compounds;
}
- public isUnlocked(state: GameState): boolean {
+ public isUnlocked = (state: GameState): boolean => {
if (this._isUnlocked) return true;
const tents = state.resource.tents;
if (
@@ -23,5 +25,5 @@ class Compound extends Infrastructure {
this._isUnlocked = true;
}
return this._isUnlocked;
- }
+ };
}
diff --git a/src/model/resource/CompoundManager.ts b/src/model/resource/CompoundManager.ts
index f877d25..ac1b875 100644
--- a/src/model/resource/CompoundManager.ts
+++ b/src/model/resource/CompoundManager.ts
@@ -1,6 +1,8 @@
///
class CompoundManager extends Job {
+ public readonly resourceKey = ResourceKey.compoundManagers;
+
constructor() {
super(
'Compound Managers',
@@ -10,16 +12,16 @@ class CompoundManager extends Job {
);
}
- public max: (state: GameState) => number = (state) => {
+ public max = (state: GameState): number => {
return (
- Math.floor(state.resource.compounds?.value ?? 0) *
+ (state.resource.compounds?.value ?? 0) *
(state.config.cfgCapacity.compounds?.compoundManagers ?? 0)
);
};
- public isUnlocked(state: GameState): boolean {
+ public isUnlocked = (state: GameState): boolean => {
if (this._isUnlocked) return true;
this._isUnlocked = state.resource.compounds?.isUnlocked(state) === true;
return this._isUnlocked;
- }
+ };
}
diff --git a/src/model/resource/Credibility.ts b/src/model/resource/Credibility.ts
index 9d37853..c6701c5 100644
--- a/src/model/resource/Credibility.ts
+++ b/src/model/resource/Credibility.ts
@@ -1,6 +1,8 @@
///
class Credibility extends Passive {
+ public readonly resourceKey = ResourceKey.credibility;
+
constructor(config: GameConfig) {
super(
'Credibility',
@@ -8,7 +10,7 @@ class Credibility extends Passive {
'credibilities',
'Affects your ability to retain followers and collect tithes.'
);
- this.value = config.cfgPassiveMax;
+ this.rawValue = config.cfgPassiveMax;
}
public static ratio(state: GameState): number {
@@ -22,9 +24,8 @@ class Credibility extends Passive {
: cred.value / cred.max(state);
}
- public max: (state: GameState) => number = (state) =>
- state.config.cfgPassiveMax;
+ public max = (state: GameState): number => state.config.cfgPassiveMax;
- public inc: (state: GameState) => number = (state) =>
+ public inc = (state: GameState): number =>
state.config.cfgCredibilityRestoreRate;
}
diff --git a/src/model/resource/CryptoCurrency.ts b/src/model/resource/CryptoCurrency.ts
index cb9be51..d3be335 100644
--- a/src/model/resource/CryptoCurrency.ts
+++ b/src/model/resource/CryptoCurrency.ts
@@ -1,6 +1,8 @@
///
class CryptoCurrency extends Purchasable {
+ public readonly resourceKey = ResourceKey.cryptoCurrency;
+
constructor(config: GameConfig) {
super(
'FaithCoin',
diff --git a/src/model/resource/CryptoMarket.ts b/src/model/resource/CryptoMarket.ts
index cfa8c7b..165bb4c 100644
--- a/src/model/resource/CryptoMarket.ts
+++ b/src/model/resource/CryptoMarket.ts
@@ -1,6 +1,8 @@
///
class CryptoMarket extends Hidden {
+ public readonly resourceKey = ResourceKey.cryptoMarket;
+
private _adjustmentTime = 0;
constructor(config: GameConfig) {
@@ -9,7 +11,7 @@ class CryptoMarket extends Hidden {
'crypto markets',
'How much money a single FaithCoin is worth'
);
- this.value = config.cfgInitialCost.cryptoCurrency ?? 0;
+ this.rawValue = config.cfgInitialCost.cryptoCurrency ?? 0;
}
public max = (state: GameState): number =>
diff --git a/src/model/resource/Follower.ts b/src/model/resource/Follower.ts
index 3538c0c..2c0d246 100644
--- a/src/model/resource/Follower.ts
+++ b/src/model/resource/Follower.ts
@@ -1,14 +1,15 @@
-///
+///
///
-class Follower implements IResource {
+class Follower extends Resource {
public readonly resourceType = ResourceType.religion;
+ public readonly resourceKey = ResourceKey.followers;
+
public readonly label = 'Your Followers';
public readonly singularName = 'follower';
public readonly pluralName = 'followers';
public readonly description = 'In you they trust.';
public readonly valueInWholeNumbers = true;
- public value = 0;
public userActions: ResourceAction[] = [
{
@@ -21,25 +22,24 @@ class Follower implements IResource {
},
];
- private _timeSinceLastLost = 0;
private _lastRecruitmentLog = 0;
private _followerSources: ResourceNumber = {};
private _followerDests: ResourceNumber = {};
private _timeSinceLastQuit = 0;
private _quitTracker: ResourceNumber = {};
- public max(state: GameState): number {
+ public max = (state: GameState): number => {
let max = state.config.cfgInitialMax.followers ?? 0;
max +=
- Math.floor(state.resource.tents?.value ?? 0) *
+ (state.resource.tents?.value ?? 0) *
(state.config.cfgCapacity.tents?.followers ?? 0);
max +=
- Math.floor(state.resource.houses?.value ?? 0) *
+ (state.resource.houses?.value ?? 0) *
(state.config.cfgCapacity.houses?.followers ?? 0);
return max;
- }
+ };
- public inc(state: GameState): number {
+ public inc = (state: GameState): number => {
let inc = 0;
// pastor recruiting
@@ -52,12 +52,12 @@ class Follower implements IResource {
if (creds?.max !== undefined) inc *= creds.value / creds.max(state);*/
return inc;
- }
+ };
- public addValue(amount: number, state: GameState): void {
+ public addValue = (amount: number, state: GameState): void => {
const oldValue = this.value;
- this.value += amount;
- const diff = Math.floor(this.value) - Math.floor(oldValue);
+ this.rawValue += amount;
+ const diff = this.value - oldValue;
if (diff > 0) {
// gained followers must come from other faiths
@@ -80,13 +80,11 @@ class Follower implements IResource {
}
}
}
- }
+ };
- public isUnlocked(_state: GameState): boolean {
- return true;
- }
+ public isUnlocked = (): boolean => true;
- public advanceAction(time: number, state: GameState): void {
+ public advanceAction = (time: number, state: GameState): void => {
// chance for some followers to quit their jobs if money === 0
const money = state.resource.money;
const totalJobs = Job.totalJobs(state);
@@ -190,7 +188,7 @@ class Follower implements IResource {
}
this._lastRecruitmentLog = state.now;
}
- }
+ };
private _recruitFollower(state: GameState): void {
// don't exceed max
diff --git a/src/model/resource/Hidden.ts b/src/model/resource/Hidden.ts
index 1c7249d..484b32a 100644
--- a/src/model/resource/Hidden.ts
+++ b/src/model/resource/Hidden.ts
@@ -1,21 +1,18 @@
-///
+///
-abstract class Hidden implements IResource {
+abstract class Hidden extends Resource {
public readonly resourceType = ResourceType.passive;
+ public readonly label = undefined;
+
public readonly valueInWholeNumbers = false;
- public value = 0;
constructor(
public readonly singularName: string,
public readonly pluralName: string,
public readonly description: string
- ) {}
-
- public addValue(amount: number, _state: GameState): void {
- this.value += amount;
+ ) {
+ super();
}
- public isUnlocked(_state: GameState): boolean {
- return true;
- }
+ public isUnlocked = (): boolean => true;
}
diff --git a/src/model/resource/House.ts b/src/model/resource/House.ts
index 2a98362..c4da4c2 100644
--- a/src/model/resource/House.ts
+++ b/src/model/resource/House.ts
@@ -1,6 +1,8 @@
///
class House extends Infrastructure {
+ public readonly resourceKey = ResourceKey.houses;
+
constructor(config: GameConfig) {
super(
'Houses',
@@ -15,13 +17,11 @@ class House extends Infrastructure {
this._costMultiplier.money = config.cfgCostMultiplier.houses;
}
- public max: (state: GameState) => number = (state) =>
- Math.floor(
- (state.resource.compounds?.value ?? 0) *
- (state.config.cfgCapacity.compounds?.houses ?? 0)
- );
+ public max = (state: GameState): number =>
+ (state.resource.compounds?.value ?? 0) *
+ (state.config.cfgCapacity.compounds?.houses ?? 0);
- public inc: (state: GameState) => number = (state) => {
+ public inc = (state: GameState): number => {
// compound managers
return (
(state.resource.compoundManagers?.value ?? 0) *
@@ -29,12 +29,12 @@ class House extends Infrastructure {
);
};
- public isUnlocked(state: GameState): boolean {
+ public isUnlocked = (state: GameState): boolean => {
if (this._isUnlocked) return true;
const compounds = state.resource.compounds;
if (compounds !== undefined && compounds.value > 0) {
this._isUnlocked = true;
}
return this._isUnlocked;
- }
+ };
}
diff --git a/src/model/resource/IResource.ts b/src/model/resource/IResource.ts
index 289f04c..1ac8511 100644
--- a/src/model/resource/IResource.ts
+++ b/src/model/resource/IResource.ts
@@ -2,13 +2,14 @@
interface IResource {
readonly resourceType: ResourceType;
+ readonly resourceKey: ResourceKey;
+
readonly label?: string;
readonly singularName: string;
readonly pluralName: string;
readonly description: string;
readonly valueInWholeNumbers: boolean;
- readonly value: number;
readonly cost?: ResourceNumber;
max?: (state: GameState) => number;
@@ -19,6 +20,8 @@ interface IResource {
addValue: (amount: number, state: GameState) => void;
isUnlocked: (state: GameState) => boolean;
+ restoreConfig: (config: ResourceConfig) => void;
emitConfig?: () => ResourceConfigValues;
- restoreConfig?: (config: ResourceConfigValues) => void;
+
+ get value(): number;
}
diff --git a/src/model/resource/Job.ts b/src/model/resource/Job.ts
index c55f0e2..b551c07 100644
--- a/src/model/resource/Job.ts
+++ b/src/model/resource/Job.ts
@@ -1,9 +1,9 @@
-///
+///
-abstract class Job implements IResource {
+abstract class Job extends Resource {
public readonly resourceType = ResourceType.job;
+
public readonly valueInWholeNumbers = true;
- public value = 0;
public readonly cost: ResourceNumber = {};
public max?: (state: GameState) => number = undefined;
@@ -39,7 +39,9 @@ abstract class Job implements IResource {
public readonly singularName: string,
public readonly pluralName: string,
public readonly description: string
- ) {}
+ ) {
+ super();
+ }
public static jobResources(state: GameState): ResourceKey[] {
return state.resources.filter((rkey) => {
@@ -74,20 +76,15 @@ abstract class Job implements IResource {
return followers - hired;
}
- public addValue(amount: number): void {
- this.value += amount;
- if (this.value < 0) this.value = 0;
- }
-
- public isUnlocked(_state: GameState): boolean {
+ public isUnlocked: (_state: GameState) => boolean = () => {
return this._isUnlocked;
- }
+ };
public advanceAction(_time: number, state: GameState): void {
// if we're out of followers then the jobs also vacate
const avail = Job.availableJobs(state);
if (avail < 0 && this.value > 0) {
- this.addValue(avail);
+ this.addValue(avail, state);
}
return;
@@ -110,7 +107,7 @@ abstract class Job implements IResource {
this.value < this.max(state) &&
state.deductCost(this.cost)
) {
- this.addValue(1);
+ this.addValue(1, state);
state.log(this._hireLog(1, state));
for (const key in this._costMultiplier) {
const rkey = key;
@@ -122,7 +119,7 @@ abstract class Job implements IResource {
private _demoteFollower(state: GameState): void {
if (this.value <= 0) return;
- this.addValue(-1);
+ this.addValue(-1, state);
state.log(this._hireLog(-1, state));
for (const key in this._costMultiplier) {
const rkey = key;
diff --git a/src/model/resource/Megachurch.ts b/src/model/resource/Megachurch.ts
index c8d39ca..bfba87c 100644
--- a/src/model/resource/Megachurch.ts
+++ b/src/model/resource/Megachurch.ts
@@ -1,6 +1,8 @@
///
class Megachurch extends Infrastructure {
+ public readonly resourceKey = ResourceKey.megaChurches;
+
constructor(config: GameConfig) {
super(
'Megachurches',
@@ -15,15 +17,15 @@ class Megachurch extends Infrastructure {
this._costMultiplier.money = config.cfgCostMultiplier.megaChurches;
}
- public max: (state: GameState) => number = (state) =>
+ public max = (state: GameState): number =>
state.config.cfgInitialMax.megaChurches ?? 0;
- public isUnlocked(state: GameState): boolean {
+ public isUnlocked = (state: GameState): boolean => {
if (this._isUnlocked) return true;
const permit = state.resource.buildingPermit;
if (permit !== undefined && permit.value > 0) {
this._isUnlocked = true;
}
return this._isUnlocked;
- }
+ };
}
diff --git a/src/model/resource/Money.ts b/src/model/resource/Money.ts
index 0dcbe3c..164f84d 100644
--- a/src/model/resource/Money.ts
+++ b/src/model/resource/Money.ts
@@ -1,7 +1,9 @@
-///
+///
+
+class Money extends Resource {
+ public readonly resourceType = ResourceType.purchasable;
+ public readonly resourceKey = ResourceKey.money;
-class Money implements IResource {
- public readonly resourceType = ResourceType.consumable;
public readonly label = 'Money';
public readonly singularName = '${}';
public readonly pluralName = '${}';
@@ -23,15 +25,14 @@ class Money implements IResource {
private _lastCollectionTime = 0;
- constructor(public value: number) {}
-
- public isUnlocked = (_state: GameState): boolean => true;
-
- public addValue(amount: number, _state: GameState): void {
- this.value += amount;
+ public constructor(initialValue: number) {
+ super();
+ this.rawValue = initialValue;
}
- public max: (state: GameState) => number = (state: GameState) => {
+ public isUnlocked = (_: GameState): boolean => true;
+
+ public max = (state: GameState): number => {
let max = state.config.cfgInitialMax.money ?? 0;
max +=
(state.resource.compounds?.value ?? 0) *
@@ -39,20 +40,20 @@ class Money implements IResource {
return max;
};
- public inc: (state: GameState) => number = (state) => {
+ public inc = (state: GameState): number => {
let inc = 0;
// tithings
inc +=
- (Math.floor(state.resource.pastors?.value ?? 0) *
- Math.floor(state.resource.followers?.value ?? 0) *
+ ((state.resource.pastors?.value ?? 0) *
+ (state.resource.followers?.value ?? 0) *
(state.config.cfgTitheAmount ?? 0) *
Credibility.ratio(state)) /
state.config.cfgTimeBetweenTithes;
// salaries
inc -=
- Math.floor(state.resource.compoundManagers?.value ?? 0) *
+ (state.resource.compoundManagers?.value ?? 0) *
(state.config.cfgSalary.compoundManagers ?? 0);
return inc;
@@ -92,11 +93,9 @@ class Money implements IResource {
if (followers !== undefined) {
state.log(
`You collected $${formatNumber(amount)} from ${formatNumber(
- Math.floor(followers.value)
+ followers.value
)} ${
- Math.floor(followers.value) > 1
- ? followers.pluralName
- : followers.singularName
+ followers.value > 1 ? followers.pluralName : followers.singularName
}.`
);
} else {
diff --git a/src/model/resource/Passive.ts b/src/model/resource/Passive.ts
index c537b6a..764f20b 100644
--- a/src/model/resource/Passive.ts
+++ b/src/model/resource/Passive.ts
@@ -1,22 +1,18 @@
-///
+///
-abstract class Passive implements IResource {
+abstract class Passive extends Resource {
public readonly resourceType = ResourceType.passive;
+
public readonly valueInWholeNumbers = false;
- public value = 0;
constructor(
public readonly label: string,
public readonly singularName: string,
public readonly pluralName: string,
public readonly description: string
- ) {}
-
- public addValue(amount: number, _state: GameState): void {
- this.value += amount;
+ ) {
+ super();
}
- public isUnlocked(_state: GameState): boolean {
- return true;
- }
+ public isUnlocked = (): boolean => true;
}
diff --git a/src/model/resource/Pastor.ts b/src/model/resource/Pastor.ts
index 9e3b356..4cd36ab 100644
--- a/src/model/resource/Pastor.ts
+++ b/src/model/resource/Pastor.ts
@@ -1,6 +1,8 @@
///
class Pastor extends Job {
+ public readonly resourceKey = ResourceKey.pastors;
+
constructor() {
super(
'Pastors',
@@ -10,19 +12,19 @@ class Pastor extends Job {
);
}
- public max: (state: GameState) => number = (state) => {
+ public max = (state: GameState): number => {
let max =
- Math.floor(state.resource.churches?.value ?? 0) *
+ (state.resource.churches?.value ?? 0) *
(state.config.cfgCapacity.churches?.pastors ?? 0);
max +=
- Math.floor(state.resource.megaChurches?.value ?? 0) *
+ (state.resource.megaChurches?.value ?? 0) *
(state.config.cfgCapacity.megaChurches?.pastors ?? 0);
- return Math.floor(max);
+ return max;
};
- public isUnlocked(state: GameState): boolean {
+ public isUnlocked = (state: GameState): boolean => {
if (this._isUnlocked) return true;
this._isUnlocked = state.resource.churches?.isUnlocked(state) === true;
return this._isUnlocked;
- }
+ };
}
diff --git a/src/model/resource/Purchasable.ts b/src/model/resource/Purchasable.ts
index b403294..419df5e 100644
--- a/src/model/resource/Purchasable.ts
+++ b/src/model/resource/Purchasable.ts
@@ -1,13 +1,13 @@
-///
+///
+
+abstract class Purchasable extends Resource {
+ public readonly resourceType: ResourceType = ResourceType.purchasable;
-abstract class Purchasable implements IResource {
- public readonly resourceType: ResourceType = ResourceType.consumable;
public valueInWholeNumbers = true;
- public value = 0;
- public readonly cost: ResourceNumber = {};
+ public cost: ResourceNumber = {};
public inc?: (state: GameState) => number = undefined;
- public max?: (_state: GameState) => number = undefined;
+ public max?: (state: GameState) => number = undefined;
public userActions: ResourceAction[] = [
{
@@ -37,6 +37,7 @@ abstract class Purchasable implements IResource {
private readonly _sellButtonText = 'Sell',
private readonly _sellDescription = `Sell a ${singularName}.`
) {
+ super();
if (canSell) {
this.userActions.push({
name: this._sellButtonText,
@@ -49,28 +50,25 @@ abstract class Purchasable implements IResource {
}
}
- public addValue(amount: number, _state: GameState): void {
- this.value += amount;
- }
-
- public isUnlocked(state: GameState): boolean {
+ public isUnlocked = (state: GameState): boolean => {
if (!this._isUnlocked && state.isPurchasable(this.cost)) {
this._isUnlocked = true;
}
return this._isUnlocked;
- }
+ };
- public advanceAction(_time: number, _state: GameState): void {
- return;
- }
-
- public emitConfig: () => ResourceConfigValues = () => {
+ public emitConfig = (): ResourceConfigValues => {
return { isUnlocked: this._isUnlocked };
};
- public restoreConfig: (config: ResourceConfigValues) => void = (config) => {
- if (typeof config.isUnlocked === 'boolean') {
- this._isUnlocked = config.isUnlocked;
+ public restoreConfig = (config: ResourceConfig): void => {
+ this.rawValue = config.value;
+ if (config.cost !== undefined) this.cost = config.cost;
+ if (
+ config.config !== undefined &&
+ typeof config.config.isUnlocked === 'boolean'
+ ) {
+ this._isUnlocked = config.config.isUnlocked;
}
};
@@ -88,7 +86,7 @@ abstract class Purchasable implements IResource {
private _purchase(state: GameState): void {
if (this.max !== undefined && this.value >= this.max(state)) return;
if (state.deductCost(this.cost)) {
- this.value += 1;
+ this.addValue(1, state);
state.log(this._purchaseLog(1, state));
for (const key in this._costMultiplier) {
const rkey = key;
@@ -118,7 +116,7 @@ abstract class Purchasable implements IResource {
costBack[rkey] = cost * -1 * multiplier;
state.deductCost(costBack);
}
- this.value -= 1;
+ this.addValue(1, state);
state.log(this._purchaseLog(-1, state));
}
}
diff --git a/src/model/resource/Religion.ts b/src/model/resource/Religion.ts
index d42bc9e..fd5cae8 100644
--- a/src/model/resource/Religion.ts
+++ b/src/model/resource/Religion.ts
@@ -1,22 +1,20 @@
-///
+///
-class Religion implements IResource {
+class Religion extends Resource {
public readonly resourceType = ResourceType.religion;
public readonly valueInWholeNumbers = true;
constructor(
+ public readonly resourceKey: ResourceKey,
public readonly label: string,
public readonly singularName: string,
public readonly pluralName: string,
public readonly description: string,
- public value: number
- ) {}
-
- public addValue(amount: number, _state: GameState): void {
- this.value += amount;
+ initialValue: number
+ ) {
+ super();
+ this.rawValue = initialValue;
}
- public isUnlocked(_state: GameState): boolean {
- return true;
- }
+ public isUnlocked = (): boolean => true;
}
diff --git a/src/model/resource/Research.ts b/src/model/resource/Research.ts
index 4d5ef0f..913af74 100644
--- a/src/model/resource/Research.ts
+++ b/src/model/resource/Research.ts
@@ -2,6 +2,7 @@
abstract class Research extends Purchasable {
public readonly resourceType = ResourceType.research;
+
public inc = undefined;
constructor(
@@ -19,8 +20,7 @@ abstract class Research extends Purchasable {
'Learn',
'Complete this research.'
);
- this.value = 0;
}
- public max: (state: GameState) => number = (_state) => 1;
+ public max = (_: GameState): number => 1;
}
diff --git a/src/model/resource/Resource.ts b/src/model/resource/Resource.ts
new file mode 100644
index 0000000..e74c718
--- /dev/null
+++ b/src/model/resource/Resource.ts
@@ -0,0 +1,31 @@
+///
+
+abstract class Resource implements IResource {
+ public cost?: ResourceNumber = undefined;
+
+ protected rawValue = 0;
+
+ public abstract readonly resourceType: ResourceType;
+ public abstract readonly resourceKey: ResourceKey;
+
+ public abstract readonly label?: string;
+ public abstract readonly singularName: string;
+ public abstract readonly pluralName: string;
+ public abstract readonly description: string;
+ public abstract valueInWholeNumbers: boolean;
+
+ public abstract isUnlocked: (state: GameState) => boolean;
+
+ public get value(): number {
+ return this.valueInWholeNumbers ? Math.floor(this.rawValue) : this.rawValue;
+ }
+
+ public addValue = (amount: number, _: GameState): void => {
+ this.rawValue += amount;
+ };
+
+ public restoreConfig = (config: ResourceConfig): void => {
+ this.rawValue = config.value;
+ this.cost = config.cost;
+ };
+}
diff --git a/src/model/resource/SharedTypes.ts b/src/model/resource/SharedTypes.ts
index 1ba92f4..946a466 100644
--- a/src/model/resource/SharedTypes.ts
+++ b/src/model/resource/SharedTypes.ts
@@ -3,7 +3,7 @@
enum ResourceType {
religion = 'religion',
job = 'job',
- consumable = 'consumable',
+ purchasable = 'purchasable',
infrastructure = 'infrastructure',
research = 'research',
passive = 'passive',
diff --git a/src/model/resource/Tent.ts b/src/model/resource/Tent.ts
index e806292..0a6661b 100644
--- a/src/model/resource/Tent.ts
+++ b/src/model/resource/Tent.ts
@@ -1,6 +1,8 @@
///
class Tent extends Infrastructure {
+ public readonly resourceKey = ResourceKey.tents;
+
constructor(config: GameConfig) {
super(
'Tents',
@@ -15,16 +17,16 @@ class Tent extends Infrastructure {
this._costMultiplier.money = config.cfgCostMultiplier.tents;
}
- public max: (state: GameState) => number = (state) => {
+ public max = (state: GameState): number => {
// ten extra tents per compound
let max = state.config.cfgInitialMax.tents ?? 0;
max +=
(state.resource.compounds?.value ?? 0) *
(state.config.cfgCapacity.compounds?.tents ?? 0);
- return Math.floor(max);
+ return max;
};
- public inc: (state: GameState) => number = (state) =>
+ public inc = (state: GameState): number =>
// compound managers
(state.resource.compoundManagers?.value ?? 0) *
(state.config.cfgBuySpeed.compoundManagers?.tents ?? 0);