@civ-clone/core-science
Version:
The basics of having the concept of research. Includes `Advance`s and associated `Registry`s and the `PlayerResearch` class to manage a `Player`s research projects and progress towards it.
156 lines (128 loc) • 4.07 kB
text/typescript
import {
AdvanceRegistry,
instance as advanceRegistryInstance,
} from './AdvanceRegistry';
import {
DataObject,
IDataObject,
} from '@civ-clone/core-data-object/DataObject';
import {
RuleRegistry,
instance as ruleRegistryInstance,
} from '@civ-clone/core-rule/RuleRegistry';
import Advance from './Advance';
import Complete from './Rules/Complete';
import Cost from './Rules/Cost';
import Player from '@civ-clone/core-player/Player';
import Requirements from './Rules/Requirements';
import { Research } from './Yields';
import Started from './Rules/Started';
export interface IPlayerResearch extends IDataObject {
add(researchYield: Research): void;
addAdvance(CompleteAdvance: typeof Advance): void;
available(): typeof Advance[];
check(): void;
complete(): Advance[];
completed(CompleteAdvance: typeof Advance): boolean;
cost(): Research;
player(): Player;
progress(): Research;
research(AdvanceToResearch: typeof Advance): void;
researching(): typeof Advance | null;
}
export class PlayerResearch extends DataObject implements IPlayerResearch {
#advanceRegistry: AdvanceRegistry;
#complete: Advance[] = [];
#researching: typeof Advance | null = null;
#player: Player;
#cost: Research = new Research(Infinity);
#progress: Research = new Research(0);
#rulesRegistry: RuleRegistry;
constructor(
player: Player,
advanceRegistry: AdvanceRegistry = advanceRegistryInstance,
rulesRegistry: RuleRegistry = ruleRegistryInstance
) {
super();
this.#advanceRegistry = advanceRegistry;
this.#player = player;
this.#rulesRegistry = rulesRegistry;
this.addKey('available', 'complete', 'cost', 'progress', 'researching');
}
add(researchYield: Research): void {
this.#progress.add(researchYield);
this.check();
}
addAdvance(CompleteAdvance: typeof Advance): void {
if (
this.#complete.some(
(advance: Advance): boolean => advance instanceof CompleteAdvance
)
) {
return;
}
if (this.#researching === CompleteAdvance) {
this.#researching = null;
}
const completedResearch = new CompleteAdvance();
this.#complete.push(completedResearch);
this.#rulesRegistry.process(Complete, this, completedResearch);
}
available(): typeof Advance[] {
const rules: Requirements[] = this.#rulesRegistry.get(Requirements);
return this.#advanceRegistry.filter(
(AvailableAdvance: typeof Advance): boolean =>
rules
.filter((rule: Requirements): boolean =>
rule.validate(AvailableAdvance, this.#complete)
)
.every(
(rule: Requirements): boolean =>
rule.process(AvailableAdvance, this.#complete) === true
) &&
!this.#complete.some(
(advance: Advance): boolean => advance instanceof AvailableAdvance
)
);
}
check(): void {
if (
this.#researching !== null &&
this.#progress.value() >= this.#cost.value()
) {
const completedResearch = new this.#researching();
this.#complete.push(completedResearch);
this.#researching = null;
this.#progress.subtract(this.#cost);
this.#cost.set(Infinity);
this.#rulesRegistry.process(Complete, this, completedResearch);
}
}
complete(): Advance[] {
return this.#complete;
}
completed(CompleteAdvance: typeof Advance): boolean {
return this.#complete.some(
(advance: Advance): boolean => advance instanceof CompleteAdvance
);
}
cost(): Research {
return this.#cost;
}
player(): Player {
return this.#player;
}
progress(): Research {
return this.#progress;
}
research(AdvanceToResearch: typeof Advance): void {
const [cost] = this.#rulesRegistry.process(Cost, AdvanceToResearch, this);
this.#cost.set(cost);
this.#researching = AdvanceToResearch;
this.#rulesRegistry.process(Started, this, AdvanceToResearch);
}
researching(): typeof Advance | null {
return this.#researching;
}
}
export default PlayerResearch;