moved all math.floor(value) logic to baseclass

This commit is contained in:
Rudis Muiznieks 2021-09-12 13:58:57 -05:00
parent 9ba7e70de4
commit 14e1b646a9
25 changed files with 209 additions and 184 deletions

View File

@ -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 {

View File

@ -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;
}

View File

@ -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 {

View File

@ -1,6 +1,8 @@
/// <reference path="./Research.ts" />
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;
}
};
}

View File

@ -1,6 +1,8 @@
/// <reference path="./Infrastructure.ts" />
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;
}
};
}

View File

@ -1,6 +1,8 @@
/// <reference path="./Infrastructure.ts" />
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;
}
};
}

View File

@ -1,6 +1,8 @@
/// <reference path="./Job.ts" />
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;
}
};
}

View File

@ -1,6 +1,8 @@
/// <reference path="./Passive.ts" />
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;
}

View File

@ -1,6 +1,8 @@
/// <reference path="./Purchasable.ts" />
class CryptoCurrency extends Purchasable {
public readonly resourceKey = ResourceKey.cryptoCurrency;
constructor(config: GameConfig) {
super(
'FaithCoin',

View File

@ -1,6 +1,8 @@
/// <reference path="./Hidden.ts" />
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 =>

View File

@ -1,14 +1,15 @@
/// <reference path="./IResource.ts" />
/// <reference path="./Resource.ts" />
/// <reference path="./Job.ts" />
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

View File

@ -1,21 +1,18 @@
/// <reference path="./IResource.ts" />
/// <reference path="./Resource.ts" />
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;
}

View File

@ -1,6 +1,8 @@
/// <reference path="./Infrastructure.ts" />
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;
}
};
}

View File

@ -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;
}

View File

@ -1,9 +1,9 @@
/// <reference path="./IResource.ts" />
/// <reference path="./Resource.ts" />
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 = <ResourceKey>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 = <ResourceKey>key;

View File

@ -1,6 +1,8 @@
/// <reference path="./Infrastructure.ts" />
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;
}
};
}

View File

@ -1,7 +1,9 @@
/// <reference path="./Purchasable.ts" />
/// <reference path="./Resource.ts" />
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 {

View File

@ -1,22 +1,18 @@
/// <reference path="./IResource.ts" />
/// <reference path="./Resource.ts" />
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;
}

View File

@ -1,6 +1,8 @@
/// <reference path="./Job.ts" />
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;
}
};
}

View File

@ -1,13 +1,13 @@
/// <reference path="./IResource.ts" />
/// <reference path="./Resource.ts" />
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 = <ResourceKey>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));
}
}

View File

@ -1,22 +1,20 @@
/// <reference path="./IResource.ts" />
/// <reference path="./Resource.ts" />
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;
}

View File

@ -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;
}

View File

@ -0,0 +1,31 @@
/// <reference path="./IResource.ts" />
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;
};
}

View File

@ -3,7 +3,7 @@
enum ResourceType {
religion = 'religion',
job = 'job',
consumable = 'consumable',
purchasable = 'purchasable',
infrastructure = 'infrastructure',
research = 'research',
passive = 'passive',

View File

@ -1,6 +1,8 @@
/// <reference path="./Infrastructure.ts" />
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);