Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/decorators/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './when.decorator.js'
export * from "./chance.decorator.js"
export * from "./chance.decorator.js"
export * from "./menu.decorator.js"
100 changes: 100 additions & 0 deletions src/decorators/common/menu.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import type { Game } from "@core"
import { CanvasPlugin, ConsolePlugin, GraphicPlugin } from "@plugins"
import type { MenuDecoratorOptions, MenuOutputType } from "@types"
import { registerAnyDecorator } from "@decorators"
import { exec } from "child_process"

/**
* Decorator marks this Geneartor method as a Menu
* Menu transform generator into Promise, that will completed
* after all choises ends.
* Your generator must return String choise text
* @param customOutput - Custom UI output plugin options
* @param { Game } core - Game, if your plugin doesnt has 'core' or 'game' property
*/
export function Menu({ customUIPropeties, browserProperties, name }: MenuDecoratorOptions, core?: Game) {
return (target: any, methodName: string, descriptor: PropertyDescriptor) => {
registerAnyDecorator(target, methodName, 'menuList', { name }, 'METHOD')

const original = descriptor.value

descriptor.value = function (...args: any[]) {
const iterator: Generator = original.apply(this, args)
const plugin = this as any
const game = plugin.core as Game ?? plugin.game as Game ?? core

if (!game) throw new Error('[Menu]: Decorator error. Game is undefined')

const plugins = game.getAllPlugins().map(plugin => plugin.name)

let outputGuiType: MenuOutputType | undefined = undefined;
let outputPluginName: string;

for (const currentPlugin of plugins) {
if (currentPlugin === ConsolePlugin.name || currentPlugin === GraphicPlugin.name) {
outputGuiType = 'APP'
outputPluginName = currentPlugin
}
else if (currentPlugin === CanvasPlugin.name) {
outputGuiType = 'BROWSER'
outputPluginName = currentPlugin
}

if (customUIPropeties && currentPlugin === customUIPropeties.name) {
outputGuiType = customUIPropeties.outputType
outputPluginName = currentPlugin
}
}

if (!outputGuiType) throw new Error('[Menu]: can`t find output UI plugin')

return new Promise((resolve, reject) => {
function step(value?: any) {
try {
const result = iterator.next(value)
const resultValue = result.value

if (result.done) return resolve(resultValue)
else {
switch(outputGuiType) {
case 'APP':
if (outputPluginName === ConsolePlugin.name) {
process.stdout.write(resultValue)
process.stdin.once('data', (data: string) => step(data))
}
else {
exec(`zenity --entry --title="${resultValue}" --text="Ваш выбор:"`, (err, out) => {
if (err) return reject(err)
else return step(out.trim())
})
}

break
case 'BROWSER':
if (!browserProperties) throw new Error('[Menu]: undefined browser properties with Browser output type')
else {
function buttonListener() {
step(browserProperties?.valueEl.value)

browserProperties?.button.removeEventListener('click', buttonListener)
}

browserProperties.button.addEventListener('click', buttonListener)
browserProperties.renderEl.innerText = resultValue
}

break
}
}
} catch (error) {
reject(error)
}
}

step()
})
}

return descriptor
}
}
11 changes: 10 additions & 1 deletion src/plugins/regenration.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Game } from "@core";
import { InjectCore, InjectLiveQuery, InjectLiveQueryObject, InjectStoreValue, OnCustomEvent, OnEvent, OnTick, When, OnTagAdded, OnTagDeleted, Chance, OnUIEvent } from "@decorators";
import { InjectCore, InjectLiveQuery, InjectLiveQueryObject, InjectStoreValue, OnCustomEvent, OnEvent, OnTick, When, OnTagAdded, OnTagDeleted, Chance, OnUIEvent, Menu } from "@decorators";
import type { IPlugin, IEventInfo } from "@interfaces";
import { anyWorldObjectIsGameObject } from "@utils";
import type { Entity, GameObject } from "@world"
Expand Down Expand Up @@ -73,6 +73,15 @@ export class RegenerationPlugin implements IPlugin {
console.log('LISTEN TAG DELETED')
}

@Menu({
name: "менюшка"
})
public *firstMenu(): Generator<any, void, string | null> {
const choise = yield 'Ваш выбор?'

console.log('ВЫБОР -', choise)
}

public install(game: Game) {
game.options.store.set(this.storePluginKey, this.HEALTH_REGEN_VALUE)
game.registerCustomEvent('regenerate', (o, e, d) => {
Expand Down
28 changes: 27 additions & 1 deletion src/types/decorators/common-decorators.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,30 @@ import type { BaseMethodDecorator } from "@types";
* Propeties for When decorator. Accepts When callback, must return true, if
* need execute this method on next game tick
*/
export type WhenDecoratorProperties = BaseMethodDecorator & { readonly when: (game: Game) => boolean }
export type WhenDecoratorProperties = BaseMethodDecorator & { readonly when: (game: Game) => boolean }

/**
* Properties for custom UI Plugin menu renderer
*/
export type MenuDecoratorCustomUIProperties = { readonly name: string, readonly outputType: MenuOutputType }

/**
* Properties for Browser Menu, where button - element to add listener menu,
* valueEl - element with value property, to read menu choise
* renderEl - Element to see innerText
*/
export type MenuDecoratorBrowserProperties = { readonly button: HTMLElement, readonly valueEl: HTMLInputElement, readonly renderEl: HTMLElement }

/**
* Type of menu decorator options
*/
export type MenuDecoratorOptions = {
readonly customUIPropeties?: MenuDecoratorCustomUIProperties;
readonly browserProperties?: MenuDecoratorBrowserProperties;
readonly name: string;
}

/**
* Types of render Menu
*/
export type MenuOutputType = 'BROWSER' | 'APP'
5 changes: 4 additions & 1 deletion test/gametest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ const [game, manager, map] = createGame({
gameGeometry: "2D"
})

game.registerPlugin([new RegenerationPlugin(20)])
const regenPlugin = new RegenerationPlugin(20)

game.registerPlugin([regenPlugin])
game.registerPlugin(new GraphicPlugin({
appName: "Моя первая игра на stemma",
assets: {
Expand All @@ -25,6 +27,7 @@ game.registerPlugin(new GraphicPlugin({
}
}))

regenPlugin.firstMenu()
const deligator = new Deligator({
observe: game,
source: game,
Expand Down
Loading