Decorators and components
This commit is contained in:
parent
6b6fd8970d
commit
ab68a5ffc6
|
|
@ -70,6 +70,10 @@ function connect() {
|
||||||
connect();
|
connect();
|
||||||
</script>`;
|
</script>`;
|
||||||
|
|
||||||
|
const POLYFILL = `<script>
|
||||||
|
if (!Symbol.metadata) Symbol.metadata = Symbol.for('Symbol.metadata');
|
||||||
|
</script>`;
|
||||||
|
|
||||||
async function buildBundle(game: string, production: boolean) {
|
async function buildBundle(game: string, production: boolean) {
|
||||||
const assetsDir = path.resolve(import.meta.dir, 'assets');
|
const assetsDir = path.resolve(import.meta.dir, 'assets');
|
||||||
const srcDir = path.resolve(import.meta.dir, '..', 'src');
|
const srcDir = path.resolve(import.meta.dir, '..', 'src');
|
||||||
|
|
@ -188,7 +192,7 @@ export async function buildHTML(game: string, {
|
||||||
}
|
}
|
||||||
|
|
||||||
script = script.replaceAll('await Promise.resolve().then(() =>', '(');
|
script = script.replaceAll('await Promise.resolve().then(() =>', '(');
|
||||||
let scriptPrefix = '';
|
let scriptPrefix = POLYFILL;
|
||||||
if (production) {
|
if (production) {
|
||||||
const minifyResult = UglifyJS.minify(script, {
|
const minifyResult = UglifyJS.minify(script, {
|
||||||
module: true,
|
module: true,
|
||||||
|
|
@ -201,7 +205,7 @@ export async function buildHTML(game: string, {
|
||||||
}
|
}
|
||||||
} else if (mobile) {
|
} else if (mobile) {
|
||||||
const eruda = await Bun.file(path.resolve(import.meta.dir, '..', 'node_modules', 'eruda', 'eruda.js')).text();
|
const eruda = await Bun.file(path.resolve(import.meta.dir, '..', 'node_modules', 'eruda', 'eruda.js')).text();
|
||||||
scriptPrefix = `<script>${eruda};\neruda.init();</script>`;
|
scriptPrefix += `<script>${eruda};\neruda.init();</script>`;
|
||||||
}
|
}
|
||||||
if (!local) {
|
if (!local) {
|
||||||
scriptPrefix += SW_SCRIPT;
|
scriptPrefix += SW_SCRIPT;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
import type { RPGActions, RPGVariables } from "../types";
|
||||||
|
import { ACTION_KEYS, VARIABLE_KEYS } from "../decorators";
|
||||||
|
|
||||||
|
export interface RPGComponent {
|
||||||
|
getVariables: () => RPGVariables;
|
||||||
|
getActions: () => RPGActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class RPGComponentBase implements RPGComponent {
|
||||||
|
getVariables(): RPGVariables {
|
||||||
|
const meta = (this.constructor as Function)[Symbol.metadata];
|
||||||
|
const keys = meta?.[VARIABLE_KEYS] as Map<string | symbol, string> | undefined;
|
||||||
|
if (!keys) return {};
|
||||||
|
const vars: RPGVariables = {};
|
||||||
|
for (const [methodKey, exportName] of keys) {
|
||||||
|
const k = String(methodKey);
|
||||||
|
const v = (this as unknown as Record<string, RPGVariables[string]>)[k];
|
||||||
|
if (v != null) {
|
||||||
|
vars[exportName] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
getActions(): RPGActions {
|
||||||
|
const meta = (this.constructor as Function)[Symbol.metadata];
|
||||||
|
const keys = meta?.[ACTION_KEYS] as Set<string | symbol> | undefined;
|
||||||
|
if (!keys) return {};
|
||||||
|
const actions: RPGActions = {};
|
||||||
|
for (const key of keys) {
|
||||||
|
const k = String(key);
|
||||||
|
actions[k] = (arg?: unknown) => (this as unknown as Record<string, (a?: unknown) => unknown>)[k](arg);
|
||||||
|
}
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RPGEntity implements RPGComponent {
|
||||||
|
private components = new Map<string, RPGComponent>();
|
||||||
|
|
||||||
|
addComponent(id: string, component: RPGComponent): void {
|
||||||
|
this.components.set(id, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeComponent(id: string): void {
|
||||||
|
this.components.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
getComponent<T extends RPGComponent>(id: string): T | undefined {
|
||||||
|
return this.components.get(id) as T | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
getVariables(): RPGVariables {
|
||||||
|
const variables: RPGVariables = {};
|
||||||
|
for (const [componentKey, component] of this.components) {
|
||||||
|
for (const [key, value] of Object.entries(component.getVariables())) {
|
||||||
|
if (value != null) {
|
||||||
|
variables[`${componentKey}.${key}`] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
getActions() {
|
||||||
|
const actions: RPGActions = {};
|
||||||
|
for (const [componentKey, component] of this.components) {
|
||||||
|
for (const [key, action] of Object.entries(component.getActions())) {
|
||||||
|
actions[`${componentKey}.${key}`] = action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,16 +1,24 @@
|
||||||
import type { InventoryOptions, InventorySlotInput, SlotId } from "./types";
|
import type { InventoryOptions, InventorySlotInput, SlotId } from "../types";
|
||||||
|
import { action } from "../decorators";
|
||||||
|
import { RPGComponentBase } from "./entity";
|
||||||
|
|
||||||
interface SlotEntry {
|
interface SlotEntry {
|
||||||
readonly slotId: SlotId;
|
readonly slotId: SlotId;
|
||||||
readonly limit: number | undefined;
|
readonly limit: number | undefined;
|
||||||
state: { itemId: string; amount: number } | null;
|
state: { itemId: string; amount: number } | null;
|
||||||
}
|
}
|
||||||
|
interface SlotUpdateArgs {
|
||||||
|
itemId: string;
|
||||||
|
amount: number;
|
||||||
|
slotId?: SlotId;
|
||||||
|
}
|
||||||
|
|
||||||
export class Inventory {
|
export class Inventory extends RPGComponentBase {
|
||||||
private readonly slots: Map<SlotId, SlotEntry>;
|
private readonly slots: Map<SlotId, SlotEntry>;
|
||||||
private readonly maxAmountPerItem: Record<string, number>;
|
private readonly maxAmountPerItem: Record<string, number>;
|
||||||
|
|
||||||
constructor(slotDefs: Array<InventorySlotInput>, options?: InventoryOptions) {
|
constructor(slotDefs: Array<InventorySlotInput>, options?: InventoryOptions) {
|
||||||
|
super();
|
||||||
this.slots = new Map(
|
this.slots = new Map(
|
||||||
slotDefs.map(def => {
|
slotDefs.map(def => {
|
||||||
const slotId = typeof def === 'object' ? def.slotId : def;
|
const slotId = typeof def === 'object' ? def.slotId : def;
|
||||||
|
|
@ -34,7 +42,8 @@ export class Inventory {
|
||||||
return this.slotCapFor(slot, itemId) - (slot.state?.amount ?? 0);
|
return this.slotCapFor(slot, itemId) - (slot.state?.amount ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
addItem(itemId: string, amount: number, slotId?: SlotId): boolean {
|
@action
|
||||||
|
addItem({ itemId, amount, slotId }: SlotUpdateArgs): boolean {
|
||||||
if (amount < 0) return false;
|
if (amount < 0) return false;
|
||||||
if (amount === 0) return true;
|
if (amount === 0) return true;
|
||||||
|
|
||||||
|
|
@ -78,7 +87,8 @@ export class Inventory {
|
||||||
return remaining === 0;
|
return remaining === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeItem(itemId: string, amount: number, slotId?: SlotId): boolean {
|
@action
|
||||||
|
removeItem({ itemId, amount, slotId }: SlotUpdateArgs): boolean {
|
||||||
if (amount < 0) return false;
|
if (amount < 0) return false;
|
||||||
if (amount === 0) return true;
|
if (amount === 0) return true;
|
||||||
|
|
||||||
|
|
@ -129,11 +139,7 @@ export class Inventory {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
getVariables(): Record<string, number> {
|
override getVariables(): Record<string, number> {
|
||||||
const result: Record<string, number> = {};
|
return Object.fromEntries(this.getItems());
|
||||||
for (const [itemId, amount] of this.getItems()) {
|
|
||||||
result[`inventory.${itemId}`] = amount;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { action, variable } from "../decorators";
|
||||||
|
import { RPGComponentBase } from "./entity";
|
||||||
|
|
||||||
|
export class Stat extends RPGComponentBase {
|
||||||
|
@variable private value: number;
|
||||||
|
@variable private maxValue: number | undefined;
|
||||||
|
|
||||||
|
constructor(value: number, maxValue?: number) {
|
||||||
|
super();
|
||||||
|
this.value = value;
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
update(amount: number) {
|
||||||
|
this.value = Math.max(0, this.value + amount);
|
||||||
|
if (this.maxValue) {
|
||||||
|
this.value = Math.min(this.value, this.maxValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import type { RPGVariables } from "../types";
|
||||||
|
import { action } from "../decorators";
|
||||||
|
import { RPGComponentBase } from "./entity";
|
||||||
|
|
||||||
|
interface Var {
|
||||||
|
key: string;
|
||||||
|
value: RPGVariables[string];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Variables extends RPGComponentBase {
|
||||||
|
private readonly variables: RPGVariables = {};
|
||||||
|
|
||||||
|
override getVariables() {
|
||||||
|
return this.variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
set({ key, value }: Var) {
|
||||||
|
this.variables[key] = value;
|
||||||
|
return this.variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
unset(key: string) {
|
||||||
|
delete this.variables[key];
|
||||||
|
return this.variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
increment({ key, value }: Var) {
|
||||||
|
const currentValue = this.variables[key] ?? 0;
|
||||||
|
if (typeof currentValue === 'number' && typeof value === 'number') {
|
||||||
|
this.variables[key] = currentValue + value;
|
||||||
|
}
|
||||||
|
return this.variables;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import type { RPGVariables } from "./types";
|
||||||
|
|
||||||
|
export const ACTION_KEYS = Symbol('rpg.actions');
|
||||||
|
export const VARIABLE_KEYS = Symbol('rpg.variables');
|
||||||
|
|
||||||
|
export function action<T extends (arg?: any) => unknown>(
|
||||||
|
target: T,
|
||||||
|
context: ClassMethodDecoratorContext<unknown, T>
|
||||||
|
): T {
|
||||||
|
const prev = context.metadata[ACTION_KEYS] as Set<string | symbol> | undefined;
|
||||||
|
context.metadata[ACTION_KEYS] = new Set(prev).add(context.name);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
type VariableContext<T extends RPGVariables[string]> =
|
||||||
|
| ClassFieldDecoratorContext<unknown, T>
|
||||||
|
| ClassGetterDecoratorContext<unknown, T>;
|
||||||
|
|
||||||
|
function registerVariable(context: VariableContext<RPGVariables[string]>, exportName: string): void {
|
||||||
|
const prev = context.metadata[VARIABLE_KEYS] as Map<string | symbol, string> | undefined;
|
||||||
|
context.metadata[VARIABLE_KEYS] = new Map(prev).set(context.name, exportName);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function variable(name: string): <T extends RPGVariables[string]>(target: undefined | (() => T), context: VariableContext<T>) => void;
|
||||||
|
export function variable<T extends RPGVariables[string]>(target: undefined, context: ClassFieldDecoratorContext<unknown, T>): void;
|
||||||
|
export function variable<T extends RPGVariables[string]>(target: () => T, context: ClassGetterDecoratorContext<unknown, T>): void;
|
||||||
|
export function variable(
|
||||||
|
nameOrTarget: string | undefined | (() => RPGVariables[string]),
|
||||||
|
context?: VariableContext<RPGVariables[string]>
|
||||||
|
): unknown {
|
||||||
|
if (typeof nameOrTarget === 'string') {
|
||||||
|
const exportName = nameOrTarget;
|
||||||
|
return (_target: unknown, ctx: VariableContext<RPGVariables[string]>) => {
|
||||||
|
registerVariable(ctx, exportName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
registerVariable(context!, String(context!.name));
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
import { RPGComponentBase } from "./components/entity";
|
||||||
import { evaluateConditions } from "./conditions";
|
import { evaluateConditions } from "./conditions";
|
||||||
|
import { action, variable } from "./decorators";
|
||||||
import {
|
import {
|
||||||
isQuest,
|
isQuest,
|
||||||
type Quest,
|
type Quest,
|
||||||
|
|
@ -10,8 +12,8 @@ import {
|
||||||
export type QuestStatus = 'inactive' | 'active' | 'completed';
|
export type QuestStatus = 'inactive' | 'active' | 'completed';
|
||||||
|
|
||||||
export interface QuestRuntimeOptions {
|
export interface QuestRuntimeOptions {
|
||||||
variables: RPGVariables;
|
getVariables(): RPGVariables;
|
||||||
actions: RPGActions;
|
getActions(): RPGActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace Quests {
|
export namespace Quests {
|
||||||
|
|
@ -37,16 +39,15 @@ export namespace Quests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QuestEngine {
|
export class QuestEngine extends RPGComponentBase {
|
||||||
private _status: QuestStatus = 'inactive';
|
@variable('status') private _status: QuestStatus = 'inactive';
|
||||||
private _stageIndex: number = 0;
|
@variable('stage') private _stageIndex: number = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly quest: Quest,
|
private readonly quest: Quest,
|
||||||
private readonly options: QuestRuntimeOptions,
|
private readonly options: QuestRuntimeOptions,
|
||||||
) {
|
) {
|
||||||
this.quest = quest;
|
super();
|
||||||
this.options = options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get id(): string {
|
get id(): string {
|
||||||
|
|
@ -54,31 +55,29 @@ export class QuestEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
isAvailable(): boolean {
|
isAvailable(): boolean {
|
||||||
return evaluateConditions(this.resolveConditions(this.quest.conditions ?? []), this.options.variables);
|
return evaluateConditions(this.quest.conditions ?? [], this.options.getVariables());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
start(): void {
|
start(): void {
|
||||||
this._status = 'active';
|
this._status = 'active';
|
||||||
this._stageIndex = 0;
|
this._stageIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveConditions(conditions: string[]): string[] {
|
@action
|
||||||
const questVar = `quest.${this.quest.id}`;
|
|
||||||
return conditions.map(c => c.replace(/^(~?)\$/, `$1${questVar}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkAndAdvance(): Promise<void> {
|
async checkAndAdvance(): Promise<void> {
|
||||||
if (this._status !== 'active') return;
|
if (this._status !== 'active') return;
|
||||||
|
|
||||||
const stage = this.quest.stages[this._stageIndex];
|
const stage = this.quest.stages[this._stageIndex];
|
||||||
if (!stage) return;
|
if (!stage) return;
|
||||||
|
|
||||||
const allDone = evaluateConditions(this.resolveConditions(stage.objectives.map(obj => obj.condition)), this.options.variables);
|
const allDone = evaluateConditions(stage.objectives.map(obj => obj.condition), this.options.getVariables());
|
||||||
|
|
||||||
if (!allDone) return;
|
if (!allDone) return;
|
||||||
|
|
||||||
|
const actions = this.options.getActions();
|
||||||
for (const action of stage.actions) {
|
for (const action of stage.actions) {
|
||||||
await this.options.actions[action.type]?.(action.arg);
|
await actions[action.type]?.(action.arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._stageIndex + 1 < this.quest.stages.length) {
|
if (this._stageIndex + 1 < this.quest.stages.length) {
|
||||||
|
|
@ -88,14 +87,6 @@ export class QuestEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getVariables(): RPGVariables {
|
|
||||||
const prefix = `quest.${this.quest.id}`;
|
|
||||||
return {
|
|
||||||
[prefix]: this._status,
|
|
||||||
[`${prefix}.stage`]: this._stageIndex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get currentStage(): QuestStage | null {
|
get currentStage(): QuestStage | null {
|
||||||
return this.quest.stages[this._stageIndex] ?? null;
|
return this.quest.stages[this._stageIndex] ?? null;
|
||||||
}
|
}
|
||||||
|
|
@ -105,32 +96,39 @@ export class QuestEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QuestManager {
|
export class QuestManager extends RPGComponentBase {
|
||||||
private readonly engines: Map<string, QuestEngine>;
|
private readonly engines: Map<string, QuestEngine>;
|
||||||
|
|
||||||
constructor(quests: Quest[], options: QuestRuntimeOptions) {
|
constructor(quests: Quest[], options: QuestRuntimeOptions) {
|
||||||
|
super();
|
||||||
this.engines = new Map(quests.map(q => [q.id, new QuestEngine(q, options)]));
|
this.engines = new Map(quests.map(q => [q.id, new QuestEngine(q, options)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
start(questId: string): void {
|
start(questId: string): void {
|
||||||
this.engines.get(questId)?.start();
|
this.engines.get(questId)?.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
async checkAndAdvance(): Promise<void> {
|
async checkAndAdvance(): Promise<void> {
|
||||||
for (const engine of this.engines.values()) {
|
for (const engine of this.engines.values()) {
|
||||||
await engine.checkAndAdvance();
|
await engine.checkAndAdvance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getVariables(): RPGVariables {
|
|
||||||
const result: RPGVariables = {};
|
|
||||||
for (const engine of this.engines.values()) {
|
|
||||||
Object.assign(result, engine.getVariables());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
getEngine(questId: string): QuestEngine | undefined {
|
getEngine(questId: string): QuestEngine | undefined {
|
||||||
return this.engines.get(questId);
|
return this.engines.get(questId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override getVariables(): RPGVariables {
|
||||||
|
const result: RPGVariables = {};
|
||||||
|
for (const [key, engine] of this.engines) {
|
||||||
|
for (const [varKey, value] of Object.entries(engine.getVariables())) {
|
||||||
|
if (value != null) {
|
||||||
|
result[`${key}.${varKey}`] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
export type RPGCondition = string;
|
export type RPGCondition = string;
|
||||||
export type RPGVariables = Record<string, string | number | boolean>;
|
export type RPGVariables = Record<string, string | number | boolean | undefined>;
|
||||||
|
|
||||||
export interface RPGAction {
|
export interface RPGAction {
|
||||||
type: string;
|
type: string;
|
||||||
arg?: string | number | boolean | null;
|
arg?: string | number | boolean | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RPGActions = Record<string, (arg?: unknown) => Promise<void> | void>;
|
export type RPGActions = Record<string, (arg?: any) => unknown>;
|
||||||
|
|
||||||
export interface DialogChoice {
|
export interface DialogChoice {
|
||||||
text: string;
|
text: string;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,41 @@
|
||||||
import { DialogEngine, Dialogs } from "@common/rpg/dialog";
|
import { RPGEntity } from "@common/rpg/components/entity";
|
||||||
import dialogYml from './dialog.yml';
|
import { Inventory } from "@common/rpg/components/inventory";
|
||||||
import { isDialog } from "@common/rpg/types";
|
import { Stat } from "@common/rpg/components/stat";
|
||||||
|
import { Variables } from "@common/rpg/components/variables";
|
||||||
|
import { QuestManager } from "@common/rpg/quest";
|
||||||
|
|
||||||
|
|
||||||
export default async function main() {
|
export default async function main() {
|
||||||
// console.log(dialogYml);
|
const game = new RPGEntity();
|
||||||
if (isDialog(dialogYml)) {
|
const player = new RPGEntity();
|
||||||
console.log(await Dialogs.coverageTest(dialogYml));
|
const inventory = new Inventory(['head', 'legs']);
|
||||||
}
|
const quests = new QuestManager([{
|
||||||
|
id: 'test',
|
||||||
|
description: 'Test quest',
|
||||||
|
title: 'Test',
|
||||||
|
stages: [],
|
||||||
|
}], game);
|
||||||
|
const vars = new Variables();
|
||||||
|
|
||||||
|
game.addComponent('variables', vars);
|
||||||
|
game.addComponent('player', player);
|
||||||
|
game.addComponent('quests', quests);
|
||||||
|
player.addComponent('inventory', inventory);
|
||||||
|
player.addComponent('health', new Stat(100));
|
||||||
|
console.log(game.getActions());
|
||||||
|
|
||||||
|
inventory.addItem({
|
||||||
|
itemId: 'helmet',
|
||||||
|
amount: 1,
|
||||||
|
slotId: 'head',
|
||||||
|
});
|
||||||
|
inventory.addItem({
|
||||||
|
itemId: 'boots',
|
||||||
|
amount: 2,
|
||||||
|
});
|
||||||
|
inventory.addItem({
|
||||||
|
itemId: 'belt',
|
||||||
|
amount: 1,
|
||||||
|
});
|
||||||
|
console.log(game.getVariables());
|
||||||
}
|
}
|
||||||
|
|
@ -551,7 +551,7 @@ export default class TileMap extends Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(dt: number) {
|
public override update(dt: number) {
|
||||||
this.players.forEach((player) => player.update(dt));
|
this.players.forEach((player) => player.update(dt));
|
||||||
this.enemies.forEach((tile) => tile.enemy!.update(dt));
|
this.enemies.forEach((tile) => tile.enemy!.update(dt));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
|
||||||
// Some stricter flags (disabled by default)
|
// Some stricter flags (disabled by default)
|
||||||
"noUnusedLocals": false,
|
"noUnusedLocals": false,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue