@rpgjs/client 5.0.0-beta.22 → 5.0.0-beta.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/Game/Object.d.ts +6 -0
  3. package/dist/Game/Object.js +58 -2
  4. package/dist/Game/Object.js.map +1 -1
  5. package/dist/RpgClientEngine.d.ts +2 -0
  6. package/dist/RpgClientEngine.js +15 -6
  7. package/dist/RpgClientEngine.js.map +1 -1
  8. package/dist/components/character-hitbox.d.ts +13 -0
  9. package/dist/components/character-hitbox.js +38 -0
  10. package/dist/components/character-hitbox.js.map +1 -0
  11. package/dist/components/character-hitbox.spec.d.ts +1 -0
  12. package/dist/components/character.ce.js +38 -29
  13. package/dist/components/character.ce.js.map +1 -1
  14. package/dist/components/gui/dialogbox/index.ce.js +31 -2
  15. package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
  16. package/dist/components/gui/hud/hud.ce.js +2 -2
  17. package/dist/components/gui/hud/hud.ce.js.map +1 -1
  18. package/dist/components/gui/menu/items-menu.ce.js +27 -4
  19. package/dist/components/gui/menu/items-menu.ce.js.map +1 -1
  20. package/dist/components/gui/menu/main-menu.ce.js +210 -155
  21. package/dist/components/gui/menu/main-menu.ce.js.map +1 -1
  22. package/dist/components/gui/save-load.ce.js +33 -4
  23. package/dist/components/gui/save-load.ce.js.map +1 -1
  24. package/dist/components/gui/shop/shop.ce.js +47 -4
  25. package/dist/components/gui/shop/shop.ce.js.map +1 -1
  26. package/dist/services/standalone.d.ts +6 -1
  27. package/dist/services/standalone.js +35 -17
  28. package/dist/services/standalone.js.map +1 -1
  29. package/dist/utils/syncHitbox.d.ts +1 -0
  30. package/dist/utils/syncHitbox.js +69 -0
  31. package/dist/utils/syncHitbox.js.map +1 -0
  32. package/dist/utils/syncHitbox.spec.d.ts +1 -0
  33. package/package.json +4 -4
  34. package/src/Game/Object.spec.ts +70 -6
  35. package/src/Game/Object.ts +90 -2
  36. package/src/RpgClientEngine.ts +19 -6
  37. package/src/components/character-hitbox.spec.ts +33 -0
  38. package/src/components/character-hitbox.ts +72 -0
  39. package/src/components/character.ce +52 -45
  40. package/src/components/gui/dialogbox/index.ce +56 -40
  41. package/src/components/gui/hud/hud.ce +2 -2
  42. package/src/components/gui/menu/items-menu.ce +12 -2
  43. package/src/components/gui/menu/main-menu.ce +37 -6
  44. package/src/components/gui/save-load.ce +48 -32
  45. package/src/components/gui/shop/shop.ce +28 -3
  46. package/src/services/standalone.spec.ts +47 -0
  47. package/src/services/standalone.ts +53 -20
  48. package/src/utils/syncHitbox.spec.ts +79 -0
  49. package/src/utils/syncHitbox.ts +104 -0
@@ -1 +1 @@
1
- {"version":3,"file":"main-menu.ce.js","names":[],"sources":["../../../../src/components/gui/menu/main-menu.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\" controls={menuControls}>\n <div class=\"rpg-ui-main-menu rpg-anim-fade-in\">\n <div class=\"rpg-ui-main-menu-layout\">\n <div class=\"rpg-ui-main-menu-left rpg-ui-menu rpg-ui-panel\">\n <div class=\"rpg-ui-menu-header\">{t(\"rpg.menu.title\")}</div>\n <div class=\"rpg-ui-main-menu-list\">\n @for ((entry,index) of menuEntries()) {\n <div\n class=\"rpg-ui-menu-item\"\n class={{disabled: isMenuDisabled(entry)}}\n data-selected={selectedMenu() === index ? \"true\" : \"false\"}\n tabindex={index}\n click={selectMenu(index)}\n >{entry.label}</div>\n }\n </div>\n </div>\n <div class=\"rpg-ui-main-menu-right\">\n @if (view() === \"menu\") {\n <div class=\"rpg-ui-panel\">\n <div class=\"rpg-ui-main-menu-section-title\">{t(\"rpg.menu.status\")}</div>\n <div class=\"rpg-ui-main-menu-status-card\">\n <div class=\"rpg-ui-main-menu-status-block\">\n <div class=\"rpg-ui-main-menu-status-label\">{t(\"rpg.menu.level\")}</div>\n <div class=\"rpg-ui-main-menu-status-value\">{level()}</div>\n </div>\n <div class=\"rpg-ui-main-menu-status-block\">\n <div class=\"rpg-ui-main-menu-status-label\">{t(\"rpg.menu.gold\")}</div>\n <div class=\"rpg-ui-main-menu-status-value\">{gold()}</div>\n </div>\n <div class=\"rpg-ui-main-menu-status-block\">\n <div class=\"rpg-ui-main-menu-status-label\">HP {hp()}/{hpMax()}</div>\n <div class=\"rpg-ui-main-menu-status-bar\">\n <div class=\"rpg-ui-main-menu-status-bar-fill hp\" style={{width: hpPercent}}></div>\n </div>\n </div>\n <div class=\"rpg-ui-main-menu-status-block\">\n <div class=\"rpg-ui-main-menu-status-label\">SP {sp()}/{spMax()}</div>\n <div class=\"rpg-ui-main-menu-status-bar\">\n <div class=\"rpg-ui-main-menu-status-bar-fill sp\" style={{width: spPercent}}></div>\n </div>\n </div>\n <div class=\"rpg-ui-main-menu-status-block\" style={{gridColumn: \"span 2\"}}>\n <div class=\"rpg-ui-main-menu-status-label\">EXP {exp()}/{expForNextlevel()}</div>\n <div class=\"rpg-ui-main-menu-status-bar\">\n <div class=\"rpg-ui-main-menu-status-bar-fill exp\" style={{width: expPercent}}></div>\n </div>\n </div>\n </div>\n <div class=\"rpg-ui-main-menu-section-title\">{t(\"rpg.menu.parameters\")}</div>\n <div class=\"rpg-ui-main-menu-params\">\n @for ((param,index) of paramsList) {\n <div class=\"rpg-ui-main-menu-param\">\n <span>{param.label}</span>\n <span>{param.value}</span>\n </div>\n }\n </div>\n </div>\n }\n @if (view() === \"items\") {\n <ItemsMenu data={data} onInteraction={onInteraction} onBack={goBack} />\n }\n @if (view() === \"skills\") {\n <SkillsMenu data={data} onBack={goBack} />\n }\n @if (view() === \"equip\") {\n <EquipMenu data={data} onInteraction={onInteraction} onBack={goBack} />\n }\n @if (view() === \"options\") {\n <OptionsMenu onBack={goBack} />\n }\n @if (view() === \"exit\") {\n <ExitMenu onConfirm={confirmExit} onBack={goBack} />\n }\n </div>\n </div>\n @if (saveOverlay) {\n <div class=\"rpg-ui-main-menu-overlay\">\n <div class=\"rpg-ui-main-menu-overlay-backdrop\"></div>\n <div class=\"rpg-ui-main-menu-overlay-content\">\n <SaveLoadComponent\n data={saveLoadData}\n onFinish={closeSaveOverlay}\n />\n </div>\n </div>\n }\n </div>\n</DOMContainer>\n\n<script>\n import { signal, computed, effect, mount } from \"canvasengine\";\n import { inject } from \"../../../core/inject\";\n import { RpgClientEngine } from \"../../../RpgClientEngine\";\n import SaveLoadComponent from \"../save-load.ce\";\n import ItemsMenu from \"./items-menu.ce\";\n import SkillsMenu from \"./skills-menu.ce\";\n import EquipMenu from \"./equip-menu.ce\";\n import OptionsMenu from \"./options-menu.ce\";\n import ExitMenu from \"./exit-menu.ce\";\n import { getEntityProp } from \"../../../utils/getEntityProp\";\n import { delay } from \"@rpgjs/common\";\n import { getKeyboardControlBind } from \"../../../services/actionInput\";\n\n const engine = inject(RpgClientEngine);\n const { t } = engine.i18n();\n const currentPlayer = engine.scene.currentPlayer;\n const keyboardControls = engine.globalConfig.keyboardControls;\n\n const { data, onFinish, onInteraction } = defineProps();\n const { menus, items, skills, equips, saveLoad } = data();\n\n const defaultMenus = [\n { id: \"items\", label: t(\"rpg.menu.items\") },\n { id: \"skills\", label: t(\"rpg.menu.skills\") },\n { id: \"equip\", label: t(\"rpg.menu.equip\") },\n { id: \"options\", label: t(\"rpg.menu.options\") },\n { id: \"save\", label: t(\"rpg.menu.save\") },\n { id: \"exit\", label: t(\"rpg.menu.exit\") }\n ];\n\n const menuEntries = computed(() => {\n if (menus && Array.isArray(menus) && menus.length) return menus;\n return defaultMenus;\n });\n\n const resolveProp = (value) => typeof value === \"function\" ? value() : value;\n const saveLoadData = computed(() => resolveProp(saveLoad) || {});\n const saveLoadMode = computed(() => saveLoadData().mode || \"load\");\n const saveLoadSlots = computed(() => saveLoadData().slots || []);\n const saveLoadCanSave = computed(() => saveLoadData().canSave !== false);\n\n const isMenuDisabled = (entry) => {\n if (!entry) return true;\n if (entry.disabled) return true;\n if (entry.enabled === false) return true;\n if (entry.id === \"save\" && !saveLoadCanSave()) return true;\n return false;\n };\n\n const selectedMenu = signal(0);\n const view = signal(\"menu\");\n const saveOverlay = signal(false);\n\n const selectableIndexes = computed(() => {\n const entries = menuEntries();\n return entries\n .map((entry, index) => (isMenuDisabled(entry) ? null : index))\n .filter((value) => value !== null);\n });\n\n effect(() => {\n const available = selectableIndexes();\n if (!available.length) return;\n const current = selectedMenu();\n if (!available.includes(current)) {\n selectedMenu.set(available[0]);\n }\n });\n\n const moveMenu = (delta) => {\n const available = selectableIndexes();\n if (!available.length) return;\n const current = selectedMenu();\n const currentIndex = Math.max(0, available.indexOf(current));\n const nextIndex = (currentIndex + delta + available.length) % available.length;\n selectedMenu.set(available[nextIndex]);\n };\n\n function selectMenu(index) {\n return function() {\n selectedMenu.set(index);\n openMenu();\n }\n }\n\n const openMenu = () => {\n const entry = menuEntries()[selectedMenu()];\n if (!entry || isMenuDisabled(entry)) return;\n if (entry.id === \"save\") {\n saveOverlay.set(true);\n return;\n }\n if (entry.id === \"exit\") {\n view.set(\"exit\");\n return;\n }\n view.set(entry.id);\n };\n\n const goBack = () => {\n delay(() => {\n view.set(\"menu\");\n });\n };\n\n const closeSaveOverlay = () => {\n delay(() => {\n saveOverlay.set(false);\n view.set(\"menu\");\n });\n };\n\n const confirmExit = () => {\n if (onInteraction) onInteraction(\"exit\");\n };\n\n const hp = getEntityProp(currentPlayer, \"hp\");\n const hpMax = getEntityProp(currentPlayer, \"params.maxHp\");\n const sp = getEntityProp(currentPlayer, \"sp\");\n const spMax = getEntityProp(currentPlayer, \"params.maxSp\");\n const level = getEntityProp(currentPlayer, \"level\");\n const exp = getEntityProp(currentPlayer, \"exp\");\n const gold = getEntityProp(currentPlayer, \"gold\");\n const expForNextlevel = computed(() => data().expForNextlevel || 0);\n const hpPercent = computed(() => {\n const max = hpMax() || 1;\n return `${Math.max(0, Math.min(100, (hp() / max) * 100))}%`;\n });\n const spPercent = computed(() => {\n const max = spMax() || 1;\n return `${Math.max(0, Math.min(100, (sp() / max) * 100))}%`;\n });\n const expPercent = computed(() => {\n const max = expForNextlevel() || 1;\n return `${Math.max(0, Math.min(100, (exp() / max) * 100))}%`;\n });\n\n const paramsList = computed(() => {\n return [\n { label: \"ATK\", value: data().playerStats.atk },\n { label: \"PDEF\", value: data().playerStats.pdef },\n { label: \"SDEF\", value: data().playerStats.sdef },\n { label: \"STR\", value: data().playerStats.str },\n { label: \"DEX\", value: data().playerStats.dex },\n { label: \"INT\", value: data().playerStats.int },\n { label: \"AGI\", value: data().playerStats.agi }\n ]\n }\n\n const menuControls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n if (saveOverlay()) return;\n if (view() !== \"menu\") return;\n moveMenu(-1);\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n if (saveOverlay()) return;\n if (view() !== \"menu\") return;\n moveMenu(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (saveOverlay()) return;\n if (view() !== \"menu\") return;\n openMenu();\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (saveOverlay()) return;\n if (view() !== \"menu\") {\n goBack();\n return;\n }\n onFinish()\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n mount((element) => {\n engine.gamePause.set(true);\n return () => {\n delay(() => {\n engine.stopProcessingInput = false;\n engine.gamePause.set(false);\n });\n }\n });\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"main-menu.ce.js","names":[],"sources":["../../../../src/components/gui/menu/main-menu.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\" controls={menuControls}>\n <div class=\"rpg-ui-main-menu rpg-anim-fade-in\" click={closeMenuFromPointer}>\n <div class=\"rpg-ui-main-menu-backdrop\"></div>\n <button class=\"rpg-ui-close-button\" type=\"button\" title=\"Close\" aria-label=\"Close menu\" click={closeMenuFromPointer}>x</button>\n <div class=\"rpg-ui-main-menu-layout\" click={stopEvent}>\n <div class=\"rpg-ui-main-menu-left rpg-ui-menu rpg-ui-panel\">\n <div class=\"rpg-ui-menu-header\">{t(\"rpg.menu.title\")}</div>\n <div class=\"rpg-ui-main-menu-list\">\n @for ((entry,index) of menuEntries()) {\n <div\n class=\"rpg-ui-menu-item\"\n class={{disabled: isMenuDisabled(entry)}}\n data-selected={selectedMenu() === index ? \"true\" : \"false\"}\n tabindex={index}\n click={selectMenu(index)}\n >{entry.label}</div>\n }\n </div>\n </div>\n <div class=\"rpg-ui-main-menu-right\">\n @if (view() === \"menu\") {\n <div class=\"rpg-ui-panel\">\n <div class=\"rpg-ui-main-menu-section-title\">{t(\"rpg.menu.status\")}</div>\n <div class=\"rpg-ui-main-menu-status-card\">\n <div class=\"rpg-ui-main-menu-status-block\">\n <div class=\"rpg-ui-main-menu-status-label\">{t(\"rpg.menu.level\")}</div>\n <div class=\"rpg-ui-main-menu-status-value\">{level()}</div>\n </div>\n <div class=\"rpg-ui-main-menu-status-block\">\n <div class=\"rpg-ui-main-menu-status-label\">{t(\"rpg.menu.gold\")}</div>\n <div class=\"rpg-ui-main-menu-status-value\">{gold()}</div>\n </div>\n <div class=\"rpg-ui-main-menu-status-block\">\n <div class=\"rpg-ui-main-menu-status-label\">HP {hp()}/{hpMax()}</div>\n <div class=\"rpg-ui-main-menu-status-bar\">\n <div class=\"rpg-ui-main-menu-status-bar-fill hp\" style={{width: hpPercent}}></div>\n </div>\n </div>\n <div class=\"rpg-ui-main-menu-status-block\">\n <div class=\"rpg-ui-main-menu-status-label\">SP {sp()}/{spMax()}</div>\n <div class=\"rpg-ui-main-menu-status-bar\">\n <div class=\"rpg-ui-main-menu-status-bar-fill sp\" style={{width: spPercent}}></div>\n </div>\n </div>\n <div class=\"rpg-ui-main-menu-status-block\" style={{gridColumn: \"span 2\"}}>\n <div class=\"rpg-ui-main-menu-status-label\">EXP {exp()}/{expForNextlevel()}</div>\n <div class=\"rpg-ui-main-menu-status-bar\">\n <div class=\"rpg-ui-main-menu-status-bar-fill exp\" style={{width: expPercent}}></div>\n </div>\n </div>\n </div>\n <div class=\"rpg-ui-main-menu-section-title\">{t(\"rpg.menu.parameters\")}</div>\n <div class=\"rpg-ui-main-menu-params\">\n @for ((param,index) of paramsList) {\n <div class=\"rpg-ui-main-menu-param\">\n <span>{param.label}</span>\n <span>{param.value}</span>\n </div>\n }\n </div>\n </div>\n }\n @if (view() === \"items\") {\n <ItemsMenu data={data} onInteraction={onInteraction} onBack={goBack} />\n }\n @if (view() === \"skills\") {\n <SkillsMenu data={data} onBack={goBack} />\n }\n @if (view() === \"equip\") {\n <EquipMenu data={data} onInteraction={onInteraction} onBack={goBack} />\n }\n @if (view() === \"options\") {\n <OptionsMenu onBack={goBack} />\n }\n @if (view() === \"exit\") {\n <ExitMenu onConfirm={confirmExit} onBack={goBack} />\n }\n </div>\n </div>\n @if (saveOverlay) {\n <div class=\"rpg-ui-main-menu-overlay\">\n <div class=\"rpg-ui-main-menu-overlay-backdrop\" click={closeSaveOverlayFromPointer}></div>\n <div class=\"rpg-ui-main-menu-overlay-content\" click={stopEvent}>\n <SaveLoadComponent\n data={saveLoadData}\n onFinish={closeSaveOverlay}\n />\n </div>\n </div>\n }\n </div>\n</DOMContainer>\n\n<script>\n import { signal, computed, effect, mount } from \"canvasengine\";\n import { inject } from \"../../../core/inject\";\n import { RpgClientEngine } from \"../../../RpgClientEngine\";\n import SaveLoadComponent from \"../save-load.ce\";\n import ItemsMenu from \"./items-menu.ce\";\n import SkillsMenu from \"./skills-menu.ce\";\n import EquipMenu from \"./equip-menu.ce\";\n import OptionsMenu from \"./options-menu.ce\";\n import ExitMenu from \"./exit-menu.ce\";\n import { getEntityProp } from \"../../../utils/getEntityProp\";\n import { delay } from \"@rpgjs/common\";\n import { getKeyboardControlBind } from \"../../../services/actionInput\";\n\n const engine = inject(RpgClientEngine);\n const { t } = engine.i18n();\n const currentPlayer = engine.scene.currentPlayer;\n const keyboardControls = engine.globalConfig.keyboardControls;\n\n const { data, onFinish, onInteraction } = defineProps();\n const { menus, items, skills, equips, saveLoad } = data();\n\n const defaultMenus = [\n { id: \"items\", label: t(\"rpg.menu.items\") },\n { id: \"skills\", label: t(\"rpg.menu.skills\") },\n { id: \"equip\", label: t(\"rpg.menu.equip\") },\n { id: \"options\", label: t(\"rpg.menu.options\") },\n { id: \"save\", label: t(\"rpg.menu.save\") },\n { id: \"exit\", label: t(\"rpg.menu.exit\") }\n ];\n\n const menuEntries = computed(() => {\n if (menus && Array.isArray(menus) && menus.length) return menus;\n return defaultMenus;\n });\n\n const resolveProp = (value) => typeof value === \"function\" ? value() : value;\n const saveLoadData = computed(() => resolveProp(saveLoad) || {});\n const saveLoadMode = computed(() => saveLoadData().mode || \"load\");\n const saveLoadSlots = computed(() => saveLoadData().slots || []);\n const saveLoadCanSave = computed(() => saveLoadData().canSave !== false);\n\n const isMenuDisabled = (entry) => {\n if (!entry) return true;\n if (entry.disabled) return true;\n if (entry.enabled === false) return true;\n if (entry.id === \"save\" && !saveLoadCanSave()) return true;\n return false;\n };\n\n const selectedMenu = signal(0);\n const view = signal(\"menu\");\n const saveOverlay = signal(false);\n\n const selectableIndexes = computed(() => {\n const entries = menuEntries();\n return entries\n .map((entry, index) => (isMenuDisabled(entry) ? null : index))\n .filter((value) => value !== null);\n });\n\n effect(() => {\n const available = selectableIndexes();\n if (!available.length) return;\n const current = selectedMenu();\n if (!available.includes(current)) {\n selectedMenu.set(available[0]);\n }\n });\n\n const moveMenu = (delta) => {\n const available = selectableIndexes();\n if (!available.length) return;\n const current = selectedMenu();\n const currentIndex = Math.max(0, available.indexOf(current));\n const nextIndex = (currentIndex + delta + available.length) % available.length;\n selectedMenu.set(available[nextIndex]);\n };\n\n function selectMenu(index) {\n return function() {\n selectedMenu.set(index);\n openMenu();\n }\n }\n\n const openMenu = () => {\n const entry = menuEntries()[selectedMenu()];\n if (!entry || isMenuDisabled(entry)) return;\n if (entry.id === \"save\") {\n saveOverlay.set(true);\n return;\n }\n if (entry.id === \"exit\") {\n view.set(\"exit\");\n return;\n }\n view.set(entry.id);\n };\n\n const goBack = () => {\n delay(() => {\n view.set(\"menu\");\n });\n };\n\n const closeSaveOverlay = () => {\n delay(() => {\n saveOverlay.set(false);\n view.set(\"menu\");\n });\n };\n\n const stopEvent = (event) => {\n event?.stopPropagation?.();\n };\n\n const closeSaveOverlayFromPointer = (event) => {\n stopEvent(event);\n closeSaveOverlay();\n };\n\n const closeMenu = () => {\n if (saveOverlay()) {\n closeSaveOverlay();\n return;\n }\n onFinish();\n };\n\n const closeMenuFromPointer = (event) => {\n stopEvent(event);\n closeMenu();\n };\n\n const confirmExit = () => {\n if (onInteraction) onInteraction(\"exit\");\n };\n\n const hp = getEntityProp(currentPlayer, \"hp\");\n const hpMax = getEntityProp(currentPlayer, \"params.maxHp\");\n const sp = getEntityProp(currentPlayer, \"sp\");\n const spMax = getEntityProp(currentPlayer, \"params.maxSp\");\n const level = getEntityProp(currentPlayer, \"level\");\n const exp = getEntityProp(currentPlayer, \"exp\");\n const gold = getEntityProp(currentPlayer, \"gold\");\n const expForNextlevel = computed(() => data().expForNextlevel || 0);\n const hpPercent = computed(() => {\n const max = hpMax() || 1;\n return `${Math.max(0, Math.min(100, (hp() / max) * 100))}%`;\n });\n const spPercent = computed(() => {\n const max = spMax() || 1;\n return `${Math.max(0, Math.min(100, (sp() / max) * 100))}%`;\n });\n const expPercent = computed(() => {\n const max = expForNextlevel() || 1;\n return `${Math.max(0, Math.min(100, (exp() / max) * 100))}%`;\n });\n\n const paramsList = computed(() => {\n return [\n { label: \"ATK\", value: data().playerStats.atk },\n { label: \"PDEF\", value: data().playerStats.pdef },\n { label: \"SDEF\", value: data().playerStats.sdef },\n { label: \"STR\", value: data().playerStats.str },\n { label: \"DEX\", value: data().playerStats.dex },\n { label: \"INT\", value: data().playerStats.int },\n { label: \"AGI\", value: data().playerStats.agi }\n ]\n }\n\n const menuControls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n if (saveOverlay()) return;\n if (view() !== \"menu\") return;\n moveMenu(-1);\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n if (saveOverlay()) return;\n if (view() !== \"menu\") return;\n moveMenu(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (saveOverlay()) return;\n if (view() !== \"menu\") return;\n openMenu();\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (saveOverlay()) return;\n if (view() !== \"menu\") {\n goBack();\n return;\n }\n onFinish()\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n mount((element) => {\n const inputLockToken = {};\n const previousStopProcessingInput = engine.stopProcessingInput;\n const previousGamePause = engine.gamePause();\n engine.__rpgMainMenuInputLock = inputLockToken;\n engine.stopProcessingInput = true;\n engine.gamePause.set(true);\n return () => {\n delay(() => {\n if (engine.__rpgMainMenuInputLock !== inputLockToken) return;\n engine.__rpgMainMenuInputLock = undefined;\n engine.stopProcessingInput = previousStopProcessingInput;\n engine.gamePause.set(previousGamePause);\n });\n }\n });\n</script>\n"],"mappings":";;;;;;;;;;;;;AAkBM,SAAQ,UAAG,SAAA;CACM,SAAQ,OAAK;CAC5B,MAAM,cAAc,eAAY,OAAA;CACf,eAAc,OAAM;CACrC,MAAM,SAAS,OAAM,eAAc;CAC3C,MAAM,EAAE,MAAM,OAAO,KAAI;CACzB,MAAM,gBAAgB,OAAO,MAAI;CACjC,MAAM,mBAAmB,OAAO,aAAY;CAC5C,MAAM,EAAE,MAAM,UAAU,kBAAkB,YAAS;CACnD,MAAM,EAAE,OAAO,OAAO,QAAQ,QAAG,aAAA,KAAA;CACjC,MAAM,eAAe;EACjB;GAAE,IAAI;GAAS,OAAO,EAAE,gBAAgB;EAAA;EACxC;GAAE,IAAI;GAAU,OAAO,EAAE,iBAAe;EAAI;EAC5C;GAAE,IAAI;GAAS,OAAO,EAAE,gBAAK;EAAA;EAC7B;GAAE,IAAI;GAAW,OAAO,EAAC,kBAAkB;EAAA;EAC3C;GAAE,IAAI;GAAQ,OAAO,EAAE,eAAe;EAAE;EACxC;GAAE,IAAI;GAAQ,OAAO,EAAE,eAAe;EAAE;CAC5C;CACA,MAAM,cAAc,eAAc;EAC9B,IAAI,SAAS,MAAM,QAAO,KAAG,KAAA,MAAA,QACzB,OAAO;EACX,OAAO;CACX,CAAC;CACD,MAAM,eAAe,UAAU,OAAM,UAAW,aAAY,MAAK,IAAM;CACvE,MAAM,eAAe,eAAa,YAAG,QAAA,KAAA,CAAA,CAAA;CAChB,eAAY,aAAA,EAAA,QAAA,MAAA;CACX,eAAW,aAAc,EAAK,SAAK,CAAA,CAAM;CAC/D,MAAM,kBAAkB,eAAa,aAAc,EAAA,YAAU,KAAO;CACpE,MAAM,kBAAkB,UAAS;EAC7B,IAAI,CAAC,OACD,OAAO;EACX,IAAI,MAAM,UACN,OAAO;EACX,IAAI,MAAM,YAAW,OACjB,OAAO;EACX,IAAI,MAAM,OAAO,UAAQ,CAAG,gBAAgB,GACxC,OAAO;EACX,OAAO;CACX;CACA,MAAM,eAAe,OAAO,CAAC;CAC7B,MAAM,OAAO,OAAO,MAAM;CAC1B,MAAM,cAAc,OAAM,KAAG;CAC7B,MAAM,oBAAmB,eAAA;EAErB,OADY,YACC,EACR,KAAK,OAAO,UAAU,eAAY,KAAA,IAAa,OAAE,KAAA,EACjD,QAAO,UAAA,UAAA,IAAA;CAChB,CAAC;CACD,aAAa;EACT,MAAM,YAAM,kBAAA;EACZ,IAAI,CAAC,UAAU,QACX;EACJ,MAAM,UAAM,aAAA;EACZ,IAAI,CAAC,UAAU,SAAS,OAAK,GACzB,aAAa,IAAA,UAAY,EAAA;CAEjC,CAAC;CACD,MAAM,YAAY,UAAG;EACjB,MAAM,YAAM,kBAAA;EACZ,IAAI,CAAC,UAAQ,QACT;EACJ,MAAK,UAAI,aAAa;EAEtB,MAAM,aADc,KAAM,IAAC,GAAK,UAAK,QAAQ,OAAA,CACf,IAAC,QAAU,UAAQ,UAAU,UAAO;EAClE,aAAa,IAAI,UAAU,UAAS;CACxC;CACA,SAAS,WAAW,OAAI;EACpB,OAAO,WAAY;GACf,aAAa,IAAA,KAAA;GACb,SAAS;EACb;CACJ;CACA,MAAM,iBAAG;EACP,MAAA,QAAY,YAAA,EAAA,aAAA;uCAEP;EACH,IAAA,MAAS,OAAQ,QAAQ;GACzB,YAAgB,IAAE,IAAM;GACxB;EACA;EACA,IAAA,MAAO,OAAU,QAAQ;GACzB,KAAO,IAAA,MAAW;GAClB;EACA;EACA,KAAA,IAAO,MAAQ,EAAC;CACpB;CACA,MAAI,eAAiB;EACjB,YAAS;;EAET,CAAA;CACJ;CACA,MAAI,yBAAsB;EACtB,YAAM;;GAEN,KAAQ,IAAK,MAAC;EACd,CAAA;;CAEJ,MAAI,aAAM,UAAe;EACrB,OAAM,kBAAmB;CAC7B;CACA,MAAM,+BAA+B,UAAU;EAC3C,UAAU,KAAC;EACX,iBAAiB;CACrB;CACA,MAAK,kBAAA;;GAED,iBAAoB;GAChB;EACJ;EACA,SAAE;;CAEN,MAAI,wBAA0B,UAAK;EAC/B,UAAM,KAAA;EACN,UAAM;CACV;CACA,MAAI,oBAAsB;qBAEtB,cAAM,MAAkB;CAC5B;CACA,MAAM,KAAK,cAAO,eAAqB,IAAA;CACvC,MAAM,QAAM,cAAgB,eAAe,cAAK;CAChD,MAAM,KAAK,cAAc,eAAW,IAAA;CACpC,MAAM,QAAQ,cAAM,eAAA,cAAA;CACpB,MAAK,QAAA,cAAA,eAAA,OAAA;;CAEL,MAAI,OAAM,cAAe,eAAS,MAAA;CAClC,MAAI,kBAAoB,eAAO,KAAA,EAAA,mBAAA,CAAA;CAC/B,MAAI,YAAM,eAAqB;;EAE3B,OAAM,GAAA,KAAA,IAAA,GAAA,KAAoB,IAAA,KAAW,GAAG,IAAC,MAAA,GAAA,CAAA,EAAA;CAC7C,CAAC;CACD,MAAM,YAAS,eAAA;EACX,MAAM,MAAM,MAAE,KAAO;EACrB,OAAO,GAAE,KAAM,IAAE,GAAK,KAAK,IAAA,KAAU,GAAA,IAAK,MAAA,GAAA,CAAA,EAAA;CAC9C,CAAC;;EAEG,MAAM,MAAM,gBAAC,KAAA;EACb,OAAI,GAAM,KAAA,IAAS,GAAG,KAAA,IAAA,KAAA,IAAmB,IAAA,MAAA,GAAA,CAAA,EAAA;CAC7C,CAAC;CACD,MAAM,aAAQ,eAAU;EACpB,OAAO;GACH;IAAE,OAAE;IAAY,OAAK,KAAA,EAAS,YAAI;GAAA;GAClC;IAAA,OAAA;IAAA,OAAA,KAAA,EAAA,YAAA;GAAA;GACF;IAAA,OAAA;IAAA,OAAA,KAAA,EAAA,YAAA;GAAA;;;;;GAEF;IAAM,OAAA;IAAY,OAAS,KAAC,EAAA,YAAA;GAAA;GACxB;IAAA,OAAM;IAAU,OAAE,KAAA,EAAA,YAAmB;GAAA;GACrC;IAAE,OAAG;IAAU,OAAQ,KAAA,EAAM,YAAA;GAAA;EACjC;CACJ,CAAC;CACD,MAAM,eAAQ,OAAa;EACvB,IAAI;GACH,QAAA;;GAED,UAAS;GACL,UAAO;IACH,IAAA,YAAgB,GAChB;IACJ,IAAA,KAAA,MAAA,QACJ;;GAEA;EACA;EACA,MAAM;GACF,QAAI;GACJ,MAAI,iBAAgB;GACpB,UAAU;GACV,UAAA;IACI,IAAA,YAAc,GACV;IACJ,IAAA,KAAM,MAAA,QACV;IACI,SAAK,CAAK;GACjB;;EAED,QAAM;GACF,MAAM,uBAAM,iBAAA,MAAA;GACZ,UAAS;IACP,IAAA,YAAA,GACL;2BAEK;IACF,SAAY;GACZ;EACJ;EACA,QAAM;GACL,MAAA,iBAAA;;IAEK,IAAA,YAAkB,GACb;IACV,IAAA,KAAA,MAAA,QAAA;;KAEK;IACF;IACA,SAAA;GACH;;EAED,SAAM,EACF,SAAI,KACR;CACJ,CAAC;CACD,OAAO,YAAC;EACJ,MAAI,iBAAU,CAAA;EACd,MAAC,8BAAA,OAAA;;EAED,OAAM,yBAAwB;EAC9B,OAAI,sBAAgB;EACpB,OAAI,UAAW,IAAA,IAAA;EACf,aAAC;;IAEK,IAAA,OAAa,2BAAO,gBAClB;IACP,OAAA,yBAAA,KAAA;;IAEO,OAAG,UAAc,IAAA,iBAAoB;GAC7C,CAAK;EACL;CACJ,CAAC;CAEG,OADc,EAAA,cAAc;EAAA,OAAa;EAAQ,QAAE;EAAA,UAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA;GAAA,OAAA;EAAA;CAAA,GAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,4BAAA;EAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA;IAAA,OAAA;IAAA,MAAA;IAAA,OAAA;IAAA,cAAA;IAAA,OAAA;GAAA;GAAA,aAAA;EAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA;IAAA,OAAA;IAAA,OAAA;GAAA;EAAA,GAAA,CAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,iDAAA;EAAA,GAAA,CAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,qBAAA;GAAA,aAAA,eAAA,EAAA,gBAAA,CAAA;EAAA,CAAA,GAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,wBAAA;EAAA,GAAA,KAAA,eAAA,YAAA,CAAA,IAAA,OAAA,UAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA;IAAA,OAAA,CAAA,oBAAA,gBAAA,EAAA,UAAA,eAAA,KAAA,EAAA,EAAA,CAAA;IAAA,iBAAA,eAAA,aAAA,MAAA,QAAA,SAAA,OAAA;IAAA,UAAA;IAAA,OAAA,WAAA,KAAA;GAAA;GAAA,aAAA,MAAA;EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,yBAAA;EAAA,GAAA;GAAA,KAAA,eAAA,KAAA,MAAA,MAAA,SAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,eAAA;GAAA,GAAA;IAAA,EAAA,YAAA;KAAA,SAAA;KAAA,OAAA,EAAA,OAAA,iCAAA;KAAA,aAAA,eAAA,EAAA,iBAAA,CAAA;IAAA,CAAA;IAAA,EAAA,YAAA;KAAA,SAAA;KAAA,OAAA,EAAA,OAAA,+BAAA;IAAA,GAAA;KAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;KAAA,GAAA,CAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;MAAA,aAAA,eAAA,EAAA,gBAAA,CAAA;KAAA,CAAA,GAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;MAAA,aAAA,eAAA,MAAA,CAAA;KAAA,CAAA,CAAA,CAAA;KAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;KAAA,GAAA,CAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;MAAA,aAAA,eAAA,EAAA,eAAA,CAAA;KAAA,CAAA,GAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;MAAA,aAAA,eAAA,KAAA,CAAA;KAAA,CAAA,CAAA,CAAA;KAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;KAAA,GAAA,CAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;MAAA,aAAA,eAAA,QAAA,GAAA,IAAA,MAAA,MAAA,CAAA;KAAA,CAAA,GAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,8BAAA;KAAA,GAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA;OAAA,OAAA;OAAA,OAAA,EAAA,OAAA,UAAA;MAAA;KAAA,CAAA,CAAA,CAAA,CAAA;KAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;KAAA,GAAA,CAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;MAAA,aAAA,eAAA,QAAA,GAAA,IAAA,MAAA,MAAA,CAAA;KAAA,CAAA,GAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,8BAAA;KAAA,GAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA;OAAA,OAAA;OAAA,OAAA,EAAA,OAAA,UAAA;MAAA;KAAA,CAAA,CAAA,CAAA,CAAA;KAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA;OAAA,OAAA;OAAA,OAAA,EAAA,YAAA,SAAA;MAAA;KAAA,GAAA,CAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,gCAAA;MAAA,aAAA,eAAA,SAAA,IAAA,IAAA,MAAA,gBAAA,CAAA;KAAA,CAAA,GAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA,EAAA,OAAA,8BAAA;KAAA,GAAA,EAAA,YAAA;MAAA,SAAA;MAAA,OAAA;OAAA,OAAA;OAAA,OAAA,EAAA,OAAA,WAAA;MAAA;KAAA,CAAA,CAAA,CAAA,CAAA;IAAA,CAAA;IAAA,EAAA,YAAA;KAAA,SAAA;KAAA,OAAA,EAAA,OAAA,iCAAA;KAAA,aAAA,eAAA,EAAA,qBAAA,CAAA;IAAA,CAAA;IAAA,EAAA,YAAA;KAAA,SAAA;KAAA,OAAA,EAAA,OAAA,0BAAA;IAAA,GAAA,KAAA,aAAA,OAAA,UAAA,EAAA,YAAA;KAAA,SAAA;KAAA,OAAA,EAAA,OAAA,yBAAA;IAAA,GAAA,CAAA,EAAA,YAAA;KAAA,SAAA;KAAA,aAAA,MAAA;IAAA,CAAA,GAAA,EAAA,YAAA;KAAA,SAAA;KAAA,aAAA,MAAA;IAAA,CAAA,CAAA,CAAA,CAAA,CAAA;GAAA,CAAA,CAAA;GAAA,KAAA,eAAA,KAAA,MAAA,OAAA,SAAA,EAAA,kBAAA;IAAA;IAAA;IAAA,QAAA;GAAA,CAAA,CAAA;GAAA,KAAA,eAAA,KAAA,MAAA,QAAA,SAAA,EAAA,kBAAA;IAAA;IAAA,QAAA;GAAA,CAAA,CAAA;GAAA,KAAA,eAAA,KAAA,MAAA,OAAA,SAAA,EAAA,kBAAA;IAAA;IAAA;IAAA,QAAA;GAAA,CAAA,CAAA;GAAA,KAAA,eAAA,KAAA,MAAA,SAAA,SAAA,EAAA,kBAAA,EAAA,QAAA,OAAA,CAAA,CAAA;GAAA,KAAA,eAAA,KAAA,MAAA,MAAA,SAAA,EAAA,kBAAA;IAAA,WAAA;IAAA,QAAA;GAAA,CAAA,CAAA;EAAA,CAAA,CAAA,CAAA;EAAA,KAAA,mBAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,2BAAA;EAAA,GAAA,CAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA;IAAA,OAAA;IAAA,OAAA;GAAA;EAAA,CAAA,GAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA;IAAA,OAAA;IAAA,OAAA;GAAA;EAAA,GAAA,EAAA,kBAAA;GAAA,MAAA;GAAA,UAAA;EAAA,CAAA,CAAA,CAAA,CAAA,CAAA;CAAA,CAAA,CACvC;AACZ;AAEA,IAAM,iBAAY"}
@@ -107,6 +107,17 @@ function component($$props) {
107
107
  triggerSelect(index);
108
108
  };
109
109
  }
110
+ const stopEvent = (event) => {
111
+ event?.stopPropagation?.();
112
+ };
113
+ const closeSaveLoad = () => {
114
+ if (onFinish) onFinish();
115
+ gui.hide(PrebuiltGui.Save);
116
+ };
117
+ const closeSaveLoadFromPointer = (event) => {
118
+ stopEvent(event);
119
+ closeSaveLoad();
120
+ };
110
121
  const controls = signal({
111
122
  up: {
112
123
  repeat: true,
@@ -133,8 +144,7 @@ function component($$props) {
133
144
  escape: {
134
145
  bind: keyboardControls.escape,
135
146
  keyDown() {
136
- if (onFinish) onFinish();
137
- gui.hide(PrebuiltGui.Save);
147
+ closeSaveLoad();
138
148
  }
139
149
  },
140
150
  gamepad: { enabled: true }
@@ -147,7 +157,26 @@ function component($$props) {
147
157
  height: "100%"
148
158
  }, h(DOMElement, {
149
159
  element: "div",
150
- attrs: { class: "rpg-ui-save-load rpg-anim-fade-in" }
160
+ attrs: {
161
+ class: "rpg-ui-save-load-layer",
162
+ click: closeSaveLoadFromPointer
163
+ }
164
+ }, [h(DOMElement, {
165
+ element: "button",
166
+ attrs: {
167
+ class: "rpg-ui-close-button",
168
+ type: "button",
169
+ title: "Close",
170
+ "aria-label": "Close save menu",
171
+ click: closeSaveLoadFromPointer
172
+ },
173
+ textContent: "x"
174
+ }), h(DOMElement, {
175
+ element: "div",
176
+ attrs: {
177
+ class: "rpg-ui-save-load rpg-anim-fade-in",
178
+ click: stopEvent
179
+ }
151
180
  }, [h(DOMElement, {
152
181
  element: "div",
153
182
  attrs: { class: "rpg-ui-save-load-header" }
@@ -205,7 +234,7 @@ function component($$props) {
205
234
  element: "div",
206
235
  attrs: { class: "rpg-ui-save-load-slot-empty" },
207
236
  textContent: computed(() => t("rpg.save.empty-slot"))
208
- }))]))))]));
237
+ }))]))))])]));
209
238
  }
210
239
  var __ce_component = component;
211
240
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"save-load.ce.js","names":[],"sources":["../../../src/components/gui/save-load.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\">\n <div class=\"rpg-ui-save-load rpg-anim-fade-in\">\n <div class=\"rpg-ui-save-load-header\">\n <div class=\"rpg-ui-save-load-title\">{title()}</div>\n <div class=\"rpg-ui-save-load-subtitle\">{subtitle()}</div>\n </div>\n <Navigation tabindex={selectedSlot} controls={controls}>\n <div class=\"rpg-ui-save-load-list\">\n @for ((item,displayIndex) of displaySlots) {\n <div\n class=\"rpg-ui-save-load-slot\"\n class={{active: selectedSlot() === displayIndex}}\n tabindex={displayIndex}\n data-slot-index={displayIndex}\n click={selectSlot(displayIndex)}\n >\n <div class=\"rpg-ui-save-load-slot-index\">{item.label}</div>\n @if (item.slot) {\n <div class=\"rpg-ui-save-load-slot-meta\">\n <div class=\"rpg-ui-save-load-slot-line\">{t(\"rpg.save.level\")}: {item.slot.level ?? \"-\"}</div>\n <div class=\"rpg-ui-save-load-slot-line\">{t(\"rpg.save.exp\")}: {item.slot.exp ?? \"-\"}</div>\n <div class=\"rpg-ui-save-load-slot-line\">{t(\"rpg.save.map\")}: {item.slot.map ?? \"-\"}</div>\n <div class=\"rpg-ui-save-load-slot-line\">{t(\"rpg.save.date\")}: {item.slot.date ?? \"-\"}</div>\n </div>\n }\n @else {\n <div class=\"rpg-ui-save-load-slot-empty\">{t(\"rpg.save.empty-slot\")}</div>\n }\n </div>\n }\n </div>\n </Navigation>\n </div>\n</DOMContainer>\n\n<script>\n import { signal, computed, effect, createTabindexNavigator, mount } from \"canvasengine\";\n import { inject } from \"../../core/inject\";\n import { RpgClientEngine } from \"../../RpgClientEngine\";\n import { SaveClientService } from \"../../services/save\";\n import { PrebuiltGui } from \"@rpgjs/common\";\n import { RpgGui } from \"../../Gui/Gui\";\n import { getKeyboardControlBind } from \"../../services/actionInput\";\n\n const engine = inject(RpgClientEngine);\n const { t } = engine.i18n();\n const saveClient = inject(SaveClientService);\n const gui = inject(RpgGui);\n const keyboardControls = engine.globalConfig.keyboardControls;\n\n const selectedSlot = signal(0);\n const DEFAULT_SLOTS = 4;\n const defaultSlots = () => Array.from({ length: DEFAULT_SLOTS }, () => null);\n const localSlots = signal(defaultSlots());\n\n const { data, onFinish } = defineProps();\n\n const title = computed(() => data().mode === \"save\" ? t(\"rpg.save.title\") : t(\"rpg.load.title\"));\n const subtitle = computed(() => data().mode === \"save\"\n ? t(\"rpg.save.subtitle\")\n : t(\"rpg.load.subtitle\")\n );\n\n const slotsValue = computed(() => localSlots());\n const displaySlots = computed(() => {\n const slots = slotsValue();\n const items = slots.map((slot, index) => ({\n kind: \"slot\",\n slot,\n slotIndex: index,\n label: t(\"rpg.save.slot\", { index: index + 1 }),\n readonly: false\n }));\n if (!data().showAutoSlot) return items;\n const index = typeof data().autoSlotIndex === \"number\" ? data().autoSlotIndex : 0;\n const autoSlot = slots[index] ?? null;\n const readonly = data().mode === \"save\";\n return [\n {\n kind: \"auto\",\n slot: autoSlot,\n slotIndex: index,\n label: data().autoSlotLabel || t(\"rpg.save.auto\"),\n readonly\n },\n ...items\n ];\n });\n const nav = createTabindexNavigator(selectedSlot, { count: () => displaySlots().length }, \"wrap\");\n\n const canSelect = (item) => {\n if (item.readonly) return false;\n if (data().mode === \"load\" && !item.slot) return false;\n return true;\n };\n\n const normalizeSlotValue = (value) => {\n if (!value) return null;\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n }\n return value;\n };\n\n const normalizeSlots = (list) => {\n if (Array.isArray(list)) {\n const length = Math.max(list.length, DEFAULT_SLOTS);\n return Array.from({ length }, (_, index) => normalizeSlotValue(list[index]));\n }\n if (!list || typeof list !== \"object\") {\n return defaultSlots();\n }\n const keys = Object.keys(list).filter((key) => /^\\d+$/.test(key));\n const indices = keys.map((key) => Number(key)).filter((index) => index >= 0);\n const maxIndex = indices.length ? Math.max(...indices) : -1;\n const length = Math.max(maxIndex + 1, DEFAULT_SLOTS);\n const slots = Array.from({ length }, () => null);\n keys.forEach((key) => {\n const index = Number(key);\n if (index < 0 || index >= length) return;\n slots[index] = normalizeSlotValue(list[key]);\n });\n return slots;\n };\n\n const hasProvidedSlots = (list) => {\n if (Array.isArray(list)) return list.length > 0;\n return !!(list && typeof list === \"object\" && Object.keys(list).length > 0);\n };\n\n const refreshSlots = async () => {\n try {\n const list = await saveClient.listSlots();\n localSlots.set(normalizeSlots(list));\n } catch (err) {\n localSlots.set(defaultSlots());\n }\n };\n\n const triggerSelect = async (displayIndex) => {\n const list = displaySlots();\n const item = list[displayIndex];\n if (!item) return;\n if (!canSelect(item)) return;\n const action = data().mode === \"save\" ? \"save\" : \"load\";\n if (action === \"save\") {\n await saveClient.saveSlot(item.slotIndex);\n await refreshSlots();\n }\n if (action === \"load\") {\n await saveClient.loadSlot(item.slotIndex);\n }\n setTimeout(() => {\n if (onFinish) onFinish();\n gui.hide(PrebuiltGui.Save);\n gui.hide(PrebuiltGui.TitleScreen);\n }, 50);\n\n };\n\n function selectSlot(index) {\n return function() {\n selectedSlot.set(index);\n triggerSelect(index);\n }\n }\n\n const controls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n nav.next(-1);\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n nav.next(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n triggerSelect(selectedSlot());\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (onFinish) onFinish();\n gui.hide(PrebuiltGui.Save);\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n mount((element) => {\n refreshSlots();\n });\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"save-load.ce.js","names":[],"sources":["../../../src/components/gui/save-load.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\">\n <div class=\"rpg-ui-save-load-layer\" click={closeSaveLoadFromPointer}>\n <button class=\"rpg-ui-close-button\" type=\"button\" title=\"Close\" aria-label=\"Close save menu\" click={closeSaveLoadFromPointer}>x</button>\n <div class=\"rpg-ui-save-load rpg-anim-fade-in\" click={stopEvent}>\n <div class=\"rpg-ui-save-load-header\">\n <div class=\"rpg-ui-save-load-title\">{title()}</div>\n <div class=\"rpg-ui-save-load-subtitle\">{subtitle()}</div>\n </div>\n <Navigation tabindex={selectedSlot} controls={controls}>\n <div class=\"rpg-ui-save-load-list\">\n @for ((item,displayIndex) of displaySlots) {\n <div\n class=\"rpg-ui-save-load-slot\"\n class={{active: selectedSlot() === displayIndex}}\n tabindex={displayIndex}\n data-slot-index={displayIndex}\n click={selectSlot(displayIndex)}\n >\n <div class=\"rpg-ui-save-load-slot-index\">{item.label}</div>\n @if (item.slot) {\n <div class=\"rpg-ui-save-load-slot-meta\">\n <div class=\"rpg-ui-save-load-slot-line\">{t(\"rpg.save.level\")}: {item.slot.level ?? \"-\"}</div>\n <div class=\"rpg-ui-save-load-slot-line\">{t(\"rpg.save.exp\")}: {item.slot.exp ?? \"-\"}</div>\n <div class=\"rpg-ui-save-load-slot-line\">{t(\"rpg.save.map\")}: {item.slot.map ?? \"-\"}</div>\n <div class=\"rpg-ui-save-load-slot-line\">{t(\"rpg.save.date\")}: {item.slot.date ?? \"-\"}</div>\n </div>\n }\n @else {\n <div class=\"rpg-ui-save-load-slot-empty\">{t(\"rpg.save.empty-slot\")}</div>\n }\n </div>\n }\n </div>\n </Navigation>\n </div>\n </div>\n</DOMContainer>\n\n<script>\n import { signal, computed, effect, createTabindexNavigator, mount } from \"canvasengine\";\n import { inject } from \"../../core/inject\";\n import { RpgClientEngine } from \"../../RpgClientEngine\";\n import { SaveClientService } from \"../../services/save\";\n import { PrebuiltGui } from \"@rpgjs/common\";\n import { RpgGui } from \"../../Gui/Gui\";\n import { getKeyboardControlBind } from \"../../services/actionInput\";\n\n const engine = inject(RpgClientEngine);\n const { t } = engine.i18n();\n const saveClient = inject(SaveClientService);\n const gui = inject(RpgGui);\n const keyboardControls = engine.globalConfig.keyboardControls;\n\n const selectedSlot = signal(0);\n const DEFAULT_SLOTS = 4;\n const defaultSlots = () => Array.from({ length: DEFAULT_SLOTS }, () => null);\n const localSlots = signal(defaultSlots());\n\n const { data, onFinish } = defineProps();\n\n const title = computed(() => data().mode === \"save\" ? t(\"rpg.save.title\") : t(\"rpg.load.title\"));\n const subtitle = computed(() => data().mode === \"save\"\n ? t(\"rpg.save.subtitle\")\n : t(\"rpg.load.subtitle\")\n );\n\n const slotsValue = computed(() => localSlots());\n const displaySlots = computed(() => {\n const slots = slotsValue();\n const items = slots.map((slot, index) => ({\n kind: \"slot\",\n slot,\n slotIndex: index,\n label: t(\"rpg.save.slot\", { index: index + 1 }),\n readonly: false\n }));\n if (!data().showAutoSlot) return items;\n const index = typeof data().autoSlotIndex === \"number\" ? data().autoSlotIndex : 0;\n const autoSlot = slots[index] ?? null;\n const readonly = data().mode === \"save\";\n return [\n {\n kind: \"auto\",\n slot: autoSlot,\n slotIndex: index,\n label: data().autoSlotLabel || t(\"rpg.save.auto\"),\n readonly\n },\n ...items\n ];\n });\n const nav = createTabindexNavigator(selectedSlot, { count: () => displaySlots().length }, \"wrap\");\n\n const canSelect = (item) => {\n if (item.readonly) return false;\n if (data().mode === \"load\" && !item.slot) return false;\n return true;\n };\n\n const normalizeSlotValue = (value) => {\n if (!value) return null;\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n }\n return value;\n };\n\n const normalizeSlots = (list) => {\n if (Array.isArray(list)) {\n const length = Math.max(list.length, DEFAULT_SLOTS);\n return Array.from({ length }, (_, index) => normalizeSlotValue(list[index]));\n }\n if (!list || typeof list !== \"object\") {\n return defaultSlots();\n }\n const keys = Object.keys(list).filter((key) => /^\\d+$/.test(key));\n const indices = keys.map((key) => Number(key)).filter((index) => index >= 0);\n const maxIndex = indices.length ? Math.max(...indices) : -1;\n const length = Math.max(maxIndex + 1, DEFAULT_SLOTS);\n const slots = Array.from({ length }, () => null);\n keys.forEach((key) => {\n const index = Number(key);\n if (index < 0 || index >= length) return;\n slots[index] = normalizeSlotValue(list[key]);\n });\n return slots;\n };\n\n const hasProvidedSlots = (list) => {\n if (Array.isArray(list)) return list.length > 0;\n return !!(list && typeof list === \"object\" && Object.keys(list).length > 0);\n };\n\n const refreshSlots = async () => {\n try {\n const list = await saveClient.listSlots();\n localSlots.set(normalizeSlots(list));\n } catch (err) {\n localSlots.set(defaultSlots());\n }\n };\n\n const triggerSelect = async (displayIndex) => {\n const list = displaySlots();\n const item = list[displayIndex];\n if (!item) return;\n if (!canSelect(item)) return;\n const action = data().mode === \"save\" ? \"save\" : \"load\";\n if (action === \"save\") {\n await saveClient.saveSlot(item.slotIndex);\n await refreshSlots();\n }\n if (action === \"load\") {\n await saveClient.loadSlot(item.slotIndex);\n }\n setTimeout(() => {\n if (onFinish) onFinish();\n gui.hide(PrebuiltGui.Save);\n gui.hide(PrebuiltGui.TitleScreen);\n }, 50);\n\n };\n\n function selectSlot(index) {\n return function() {\n selectedSlot.set(index);\n triggerSelect(index);\n }\n }\n\n const stopEvent = (event) => {\n event?.stopPropagation?.();\n };\n\n const closeSaveLoad = () => {\n if (onFinish) onFinish();\n gui.hide(PrebuiltGui.Save);\n };\n\n const closeSaveLoadFromPointer = (event) => {\n stopEvent(event);\n closeSaveLoad();\n };\n\n const controls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n nav.next(-1);\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n nav.next(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n triggerSelect(selectedSlot());\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n closeSaveLoad();\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n mount((element) => {\n refreshSlots();\n });\n</script>\n"],"mappings":"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"}
@@ -177,6 +177,24 @@ function component($$props) {
177
177
  quantityDialogOpen.set(false);
178
178
  };
179
179
  }
180
+ const stopEvent = (event) => {
181
+ event?.stopPropagation?.();
182
+ };
183
+ const closeQuantityDialogFromPointer = (event) => {
184
+ stopEvent(event);
185
+ quantityDialogOpen.set(false);
186
+ };
187
+ const closeShop = () => {
188
+ if (quantityDialogOpen()) {
189
+ quantityDialogOpen.set(false);
190
+ return;
191
+ }
192
+ onFinish();
193
+ };
194
+ const closeShopFromPointer = (event) => {
195
+ stopEvent(event);
196
+ closeShop();
197
+ };
180
198
  function confirmTrade() {
181
199
  return function() {
182
200
  const item = currentItem();
@@ -312,7 +330,26 @@ function component($$props) {
312
330
  height: "100%"
313
331
  }, h(DOMElement, {
314
332
  element: "div",
315
- attrs: { class: "rpg-shop-container rpg-anim-fade-in" }
333
+ attrs: {
334
+ class: "rpg-shop-layer",
335
+ click: closeShopFromPointer
336
+ }
337
+ }, [h(DOMElement, {
338
+ element: "button",
339
+ attrs: {
340
+ class: "rpg-ui-close-button",
341
+ type: "button",
342
+ title: "Close",
343
+ "aria-label": "Close shop",
344
+ click: closeShopFromPointer
345
+ },
346
+ textContent: "x"
347
+ }), h(DOMElement, {
348
+ element: "div",
349
+ attrs: {
350
+ class: "rpg-shop-container rpg-anim-fade-in",
351
+ click: stopEvent
352
+ }
316
353
  }, [h(DOMElement, {
317
354
  element: "div",
318
355
  attrs: { class: "rpg-shop-header" }
@@ -527,10 +564,16 @@ function component($$props) {
527
564
  })
528
565
  ])])])), cond(quantityDialogOpen, () => h(DOMElement, {
529
566
  element: "div",
530
- attrs: { class: "rpg-shop-modal" }
567
+ attrs: {
568
+ class: "rpg-shop-modal",
569
+ click: closeQuantityDialogFromPointer
570
+ }
531
571
  }, h(DOMElement, {
532
572
  element: "div",
533
- attrs: { class: "rpg-shop-modal-card" }
573
+ attrs: {
574
+ class: "rpg-shop-modal-card",
575
+ click: stopEvent
576
+ }
534
577
  }, [
535
578
  h(DOMElement, {
536
579
  element: "div",
@@ -608,7 +651,7 @@ function component($$props) {
608
651
  },
609
652
  textContent: computed(() => actionLabel() + " x" + quantity())
610
653
  })])
611
- ])))]))]));
654
+ ])))]))])]));
612
655
  }
613
656
  var __ce_component = component;
614
657
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"shop.ce.js","names":[],"sources":["../../../../src/components/gui/shop/shop.ce"],"sourcesContent":[" <DOMContainer width=\"100%\" height=\"100%\">\n <div class=\"rpg-shop-container rpg-anim-fade-in\">\n <div class=\"rpg-shop-header\">\n <div class=\"rpg-shop-merchant\">\n <div>\n @if (hasFace) {\n <div class=\"rpg-shop-merchant-avatar\">\n <DOMSprite \n sheet={faceSheet(face().id, face().expression)} \n width=\"50px\"\n height=\"50px\"\n objectFit=\"contain\"\n /> \n </div>\n }\n </div>\n <div class=\"rpg-shop-merchant-info\">\n <p>{{ shopMessage() }}</p>\n </div>\n </div>\n <div class=\"rpg-shop-gold\">\n {{ gold() }} {{ goldTerm }}\n </div>\n </div>\n\n <div class=\"rpg-shop-body\">\n <div class=\"rpg-shop-left\">\n @if (tradeView() === 'mode') {\n <div class=\"rpg-shop-content rpg-shop-content-mode\">\n <div class=\"rpg-shop-details rpg-shop-details-mode\">\n <div class=\"rpg-shop-details-header\">\n <div class=\"rpg-shop-details-icon\">🛒</div>\n <h2 style=\"margin: 0;\">{t(\"rpg.shop.choose-action\")}</h2>\n </div>\n <div class=\"rpg-shop-trade\">\n <Navigation tabindex={selectedModeIndex} controls={modeControls}>\n <div class=\"rpg-shop-tabs rpg-shop-trade-tabs\">\n <div\n class=\"rpg-shop-tab\"\n class={{active: selectedModeIndex() === 0}}\n click={selectMode('buy')}\n >{t(\"rpg.shop.buy\")}</div>\n <div\n class=\"rpg-shop-tab\"\n class={{active: selectedModeIndex() === 1}}\n click={selectMode('sell')}\n >{t(\"rpg.shop.sell\")}</div>\n </div>\n </Navigation>\n </div>\n </div>\n </div>\n }\n @else {\n <div>\n <Navigation tabindex={selectedTab} controls={tabControls}> \n <div class=\"rpg-shop-tabs\">\n @for ((tab,index) of tabs) {\n <div \n class=\"rpg-shop-tab\" \n class={{active: selectedTab() === index}} \n tabindex={index} \n click={selectTab(index)}\n >{{ tab.label }}</div>\n }\n </div>\n </Navigation>\n\n <div class=\"rpg-shop-content\">\n <div class=\"rpg-shop-grid\">\n <Navigation tabindex={selectedItem} controls={itemControls}> \n @for ((item,index) of filteredItems) { \n <div class=\"rpg-shop-card\" class={{disabled: isItemDisabled(item), selected: selectedItem() === index}} tabindex={index} click={selectItem(index)}>\n <div class=\"rpg-shop-card-icon\">\n @if (item.icon) {\n <DOMSprite \n sheet={iconSheet(item.icon)} \n playing=\"default\" \n width=\"48px\"\n height=\"48px\"\n objectFit=\"contain\"\n />\n }\n </div>\n <div class=\"rpg-shop-card-name\">{{ item.name }}</div>\n <div class=\"rpg-shop-card-price\">{{ item.price }} {{ goldTerm }}</div>\n @if (item.quantity !== undefined) {\n <div class=\"rpg-shop-card-qty\">x{{ item.quantity }}</div>\n }\n @if (item.equipped) {\n <div class=\"rpg-shop-card-tag\">{t(\"rpg.shop.equipped\")}</div>\n }\n </div>\n }\n </Navigation>\n </div>\n\n <div class=\"rpg-shop-details\">\n <div class=\"rpg-shop-details-header\">\n <div class=\"rpg-shop-details-icon\">\n <DOMSprite \n sheet={iconSheet(currentItem()?.icon)} \n playing=\"default\" \n width=\"80px\"\n height=\"80px\"\n objectFit=\"contain\"\n />\n </div>\n <h2 style=\"margin: 0;\">{{ currentItem()?.name || \"\" }}</h2>\n <p style=\"color: #ffd700; font-weight: bold; margin: 8px 0;\">{{ currentItem()?.price ?? 0 }} {{ goldTerm }}</p>\n @if (currentItem()?.quantity !== undefined) {\n <div class=\"rpg-shop-details-qty\">{t(\"rpg.shop.qty\")}: x{{ currentItem()?.quantity }}</div>\n }\n </div>\n <div>\n @if (currentItem()?.equipped) {\n <div class=\"rpg-shop-equipped\">{t(\"rpg.shop.already-equipped\")}</div>\n }\n </div>\n <div class=\"rpg-shop-details-desc\">\n {{ currentItem()?.description || \"\" }}\n </div>\n <div>\n @if (displayStats().length > 0) {\n <div class=\"rpg-shop-stats\">\n @for ((stat,index) of displayStats) {\n <div class=\"rpg-shop-stat\" class={{positive: stat.delta > 0, negative: stat.delta < 0}}>\n <div class=\"rpg-shop-stat-key\">{{ stat.label }}</div>\n <div class=\"rpg-shop-stat-value\">\n {{ stat.delta > 0 ? '+' : '' }}{{ stat.delta }}\n </div>\n @if (stat.current !== undefined) {\n <div class=\"rpg-shop-stat-current\">{{ stat.current }} → {{ stat.next }}</div>\n }\n </div>\n }\n </div>\n }\n </div>\n <button class=\"rpg-shop-btn\" click={backToMode()}>{t(\"rpg.shop.back\")}</button>\n </div>\n </div>\n </div>\n }\n @if (quantityDialogOpen) {\n <div class=\"rpg-shop-modal\">\n <div class=\"rpg-shop-modal-card\">\n <div class=\"rpg-shop-modal-title\">{{ actionLabel }}</div>\n <div class=\"rpg-shop-modal-item\">{{ currentItem()?.name || \"\" }}</div>\n @if (currentItem()?.quantity !== undefined) {\n <div class=\"rpg-shop-modal-qty\">{t(\"rpg.shop.available\")}: x{{ currentItem()?.quantity }}</div>\n }\n <div class=\"rpg-shop-quantity\">\n <div class=\"rpg-shop-quantity-label\">{t(\"rpg.shop.quantity\")}</div>\n <div class=\"rpg-shop-quantity-controls\">\n <button class=\"rpg-shop-btn\" click={changeQuantity(-1)}>-</button>\n <div class=\"rpg-shop-quantity-value\">{{ quantity }}</div>\n <button class=\"rpg-shop-btn\" click={changeQuantity(1)}>+</button>\n </div>\n </div>\n <div class=\"rpg-shop-modal-total\">\n <span>{t(\"rpg.shop.total\")}</span>\n <span>{{ totalPrice() }} {{ goldTerm }}</span>\n </div>\n <div class=\"rpg-shop-modal-actions\">\n <button class=\"rpg-shop-btn rpg-shop-btn-secondary\" click={closeQuantityDialog()}>{t(\"rpg.menu.cancel\")}</button>\n <button class=\"rpg-shop-btn\" click={confirmTrade()}>\n {{ actionLabel() }} x{{ quantity() }}\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </DOMContainer>\n\n<script>\n import { mount, signal, computed, createTabindexNavigator, effect } from \"canvasengine\";\n import { inject } from \"../../../core/inject\";\n import { RpgClientEngine } from \"../../../RpgClientEngine\";\n import { getKeyboardControlBind } from \"../../../services/actionInput\";\n\n const engine = inject(RpgClientEngine)\n const { t } = engine.i18n()\n const currentPlayer = engine.scene.currentPlayer\n const keyboardControls = engine.globalConfig.keyboardControls\n const iconSheet = (iconId) => ({\n definition: engine.getSpriteSheet(iconId),\n playing: \"default\"\n })\n const goldTerm = engine.globalConfig.goldTerm || 'G'\n\n const selectedItem = signal(0)\n const selectedTab = signal(0)\n const tradeMode = signal('buy')\n const tradeView = signal('mode')\n const selectedModeIndex = signal(0)\n const quantity = signal(1)\n const quantityDialogOpen = signal(false)\n const defaultMessage = t(\"rpg.shop.default-message\")\n const tabs = [\n { id: 'item', label: t(\"rpg.menu.items\") },\n { id: 'weapon', label: t(\"rpg.menu.weapons\") },\n { id: 'armor', label: t(\"rpg.menu.armor\") }\n ]\n\n const { data, onInteraction , onFinish } = defineProps()\n\n const resolveProp = (value) => typeof value === \"function\" ? value() : value\n const guiData = computed(() => resolveProp(data) || {})\n const shopMessage = computed(() => {\n const message = resolveProp(guiData().message)\n return message ? String(message) : defaultMessage\n })\n const face = computed(() => resolveProp(guiData().face))\n const hasFace = computed(() => {\n const value = face()\n return value && value.id\n })\n const buyItems = computed(() => guiData().items || [])\n const sellItems = computed(() => guiData().sellItems || [])\n const activeItems = computed(() => tradeMode() === 'buy' ? buyItems() : sellItems())\n const filteredItems = computed(() => {\n const tab = tabs[selectedTab()]\n const items = activeItems()\n if (!tab) return []\n return items.filter((item) => item?.type === tab.id)\n })\n const currentItem = computed(() => filteredItems()[selectedItem()])\n const gold = computed(() => currentPlayer()._gold())\n const actionLabel = computed(() => tradeMode() === 'buy' ? t(\"rpg.shop.buy\") : t(\"rpg.shop.sell\"))\n const faceSheet = (graphicId, animationName) => ({\n definition: engine.getSpriteSheet(graphicId),\n playing: animationName || \"default\"\n })\n const maxQuantity = computed(() => {\n const item = currentItem()\n if (!item) return 0\n const price = item?.price || 0\n if (price <= 0) return 0\n if (tradeMode() === 'sell') {\n const qty = item?.quantity ?? 0\n return Math.max(0, qty)\n }\n return Math.max(1, Math.floor(gold() / price))\n })\n const totalPrice = computed(() => {\n const price = currentItem()?.price || 0\n return price * quantity()\n })\n const displayStats = computed(() => {\n const stats = currentItem()?.stats || {}\n const params = guiData().playerParams || {}\n const order = ['atk', 'def', 'pdef', 'sdef', 'str', 'dex', 'int', 'agi', 'maxHp', 'maxSp']\n const labels = {\n atk: 'ATK',\n def: 'DEF',\n pdef: 'PDEF',\n sdef: 'SDEF',\n str: 'STR',\n dex: 'DEX',\n int: 'INT',\n agi: 'AGI',\n maxHp: 'MAX HP',\n maxSp: 'MAX SP'\n }\n const orderedKeys = order.filter((key) => stats[key] !== undefined)\n const extraKeys = Object.keys(stats).filter((key) => !order.includes(key))\n const keys = orderedKeys.concat(extraKeys)\n const list = []\n for (const key of keys) {\n const delta = stats[key]\n if (delta === undefined || delta === 0) continue\n let current = params[key]\n if (current === undefined && key === 'def') current = params.pdef\n const next = current !== undefined ? current + delta : undefined\n list.push({\n key,\n label: labels[key] || key.toUpperCase(),\n delta,\n current,\n next\n })\n }\n return list\n })\n const nav = createTabindexNavigator(selectedItem, { count: () => filteredItems().length }, 'wrap')\n const navTab = createTabindexNavigator(selectedTab, { count: () => tabs.length }, 'wrap')\n const navMode = createTabindexNavigator(selectedModeIndex, { count: () => 2 }, 'wrap')\n\n function selectItem(index) {\n return function() {\n selectedItem.set(index)\n quantity.set(1)\n if (!isItemDisabled(filteredItems()[index])) {\n quantityDialogOpen.set(true)\n }\n }\n }\n\n function selectTab(index) {\n return function() {\n selectedTab.set(index)\n selectedItem.set(0)\n }\n }\n\n function selectMode(mode) {\n return function() {\n tradeMode.set(mode)\n selectedModeIndex.set(mode === 'buy' ? 0 : 1)\n selectedItem.set(0)\n quantity.set(1)\n tradeView.set('items')\n }\n }\n\n function isItemDisabled(item) {\n if (!item) return true\n const price = item?.price || 0\n if (price <= 0) return true\n if (tradeMode() === 'sell') {\n const qty = item?.quantity ?? 0\n return qty <= 0\n }\n return gold() < price\n }\n\n function backToMode() {\n return function() {\n tradeView.set('mode')\n }\n }\n\n function changeQuantity(delta) {\n return function() {\n const limit = maxQuantity()\n if (limit <= 0) return\n const nextValue = Math.max(1, Math.min(limit, quantity() + delta))\n if (nextValue !== quantity()) {\n quantity.set(nextValue)\n }\n }\n }\n\n function closeQuantityDialog() {\n return function() {\n quantityDialogOpen.set(false)\n }\n }\n\n function confirmTrade() {\n return function() {\n const item = currentItem()\n if (!item || isItemDisabled(item)) {\n quantityDialogOpen.set(false)\n return\n }\n const action = tradeMode() === 'buy' ? 'buyItem' : 'sellItem'\n onInteraction(action, { id: item.id, nb: quantity() })\n quantityDialogOpen.set(false)\n }\n }\n\n effect(() => {\n const count = filteredItems().length\n if (selectedItem() >= count) {\n selectedItem.set(Math.max(0, count - 1))\n }\n })\n\n const modeControls = signal({\n left: {\n repeat: true,\n bind: keyboardControls.left,\n throttle: 150,\n keyDown() {\n navMode.next(-1)\n }\n },\n right: {\n repeat: true,\n bind: keyboardControls.right,\n throttle: 150,\n keyDown() {\n navMode.next(1)\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n const mode = selectedModeIndex() === 0 ? 'buy' : 'sell'\n tradeMode.set(mode)\n selectedItem.set(0)\n quantity.set(1)\n tradeView.set('items')\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n onFinish()\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n const itemControls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n if (quantityDialogOpen()) {\n changeQuantity(1)()\n return\n }\n nav.next(-1)\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n if (quantityDialogOpen()) {\n changeQuantity(-1)()\n return\n }\n nav.next(1)\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (quantityDialogOpen()) {\n const item = currentItem()\n if (!item || isItemDisabled(item)) {\n quantityDialogOpen.set(false)\n return\n }\n const action = tradeMode() === 'buy' ? 'buyItem' : 'sellItem'\n onInteraction(action, { id: item.id, nb: quantity() })\n quantityDialogOpen.set(false)\n return\n }\n const item = currentItem()\n if (!isItemDisabled(item)) {\n quantityDialogOpen.set(true)\n }\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (quantityDialogOpen()) {\n quantityDialogOpen.set(false)\n return\n }\n tradeView.set('mode')\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n const tabControls = signal({\n left: {\n repeat: true,\n bind: keyboardControls.left,\n throttle: 150,\n keyDown() {\n if (quantityDialogOpen()) return\n navTab.next(-1)\n }\n },\n right: {\n repeat: true,\n bind: keyboardControls.right,\n throttle: 150,\n keyDown() {\n if (quantityDialogOpen()) return\n navTab.next(1)\n }\n },\n gamepad: {\n enabled: true\n }\n })\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"shop.ce.js","names":[],"sources":["../../../../src/components/gui/shop/shop.ce"],"sourcesContent":[" <DOMContainer width=\"100%\" height=\"100%\">\n <div class=\"rpg-shop-layer\" click={closeShopFromPointer}>\n <button class=\"rpg-ui-close-button\" type=\"button\" title=\"Close\" aria-label=\"Close shop\" click={closeShopFromPointer}>x</button>\n <div class=\"rpg-shop-container rpg-anim-fade-in\" click={stopEvent}>\n <div class=\"rpg-shop-header\">\n <div class=\"rpg-shop-merchant\">\n <div>\n @if (hasFace) {\n <div class=\"rpg-shop-merchant-avatar\">\n <DOMSprite \n sheet={faceSheet(face().id, face().expression)} \n width=\"50px\"\n height=\"50px\"\n objectFit=\"contain\"\n /> \n </div>\n }\n </div>\n <div class=\"rpg-shop-merchant-info\">\n <p>{{ shopMessage() }}</p>\n </div>\n </div>\n <div class=\"rpg-shop-gold\">\n {{ gold() }} {{ goldTerm }}\n </div>\n </div>\n\n <div class=\"rpg-shop-body\">\n <div class=\"rpg-shop-left\">\n @if (tradeView() === 'mode') {\n <div class=\"rpg-shop-content rpg-shop-content-mode\">\n <div class=\"rpg-shop-details rpg-shop-details-mode\">\n <div class=\"rpg-shop-details-header\">\n <div class=\"rpg-shop-details-icon\">🛒</div>\n <h2 style=\"margin: 0;\">{t(\"rpg.shop.choose-action\")}</h2>\n </div>\n <div class=\"rpg-shop-trade\">\n <Navigation tabindex={selectedModeIndex} controls={modeControls}>\n <div class=\"rpg-shop-tabs rpg-shop-trade-tabs\">\n <div\n class=\"rpg-shop-tab\"\n class={{active: selectedModeIndex() === 0}}\n click={selectMode('buy')}\n >{t(\"rpg.shop.buy\")}</div>\n <div\n class=\"rpg-shop-tab\"\n class={{active: selectedModeIndex() === 1}}\n click={selectMode('sell')}\n >{t(\"rpg.shop.sell\")}</div>\n </div>\n </Navigation>\n </div>\n </div>\n </div>\n }\n @else {\n <div>\n <Navigation tabindex={selectedTab} controls={tabControls}> \n <div class=\"rpg-shop-tabs\">\n @for ((tab,index) of tabs) {\n <div \n class=\"rpg-shop-tab\" \n class={{active: selectedTab() === index}} \n tabindex={index} \n click={selectTab(index)}\n >{{ tab.label }}</div>\n }\n </div>\n </Navigation>\n\n <div class=\"rpg-shop-content\">\n <div class=\"rpg-shop-grid\">\n <Navigation tabindex={selectedItem} controls={itemControls}> \n @for ((item,index) of filteredItems) { \n <div class=\"rpg-shop-card\" class={{disabled: isItemDisabled(item), selected: selectedItem() === index}} tabindex={index} click={selectItem(index)}>\n <div class=\"rpg-shop-card-icon\">\n @if (item.icon) {\n <DOMSprite \n sheet={iconSheet(item.icon)} \n playing=\"default\" \n width=\"48px\"\n height=\"48px\"\n objectFit=\"contain\"\n />\n }\n </div>\n <div class=\"rpg-shop-card-name\">{{ item.name }}</div>\n <div class=\"rpg-shop-card-price\">{{ item.price }} {{ goldTerm }}</div>\n @if (item.quantity !== undefined) {\n <div class=\"rpg-shop-card-qty\">x{{ item.quantity }}</div>\n }\n @if (item.equipped) {\n <div class=\"rpg-shop-card-tag\">{t(\"rpg.shop.equipped\")}</div>\n }\n </div>\n }\n </Navigation>\n </div>\n\n <div class=\"rpg-shop-details\">\n <div class=\"rpg-shop-details-header\">\n <div class=\"rpg-shop-details-icon\">\n <DOMSprite \n sheet={iconSheet(currentItem()?.icon)} \n playing=\"default\" \n width=\"80px\"\n height=\"80px\"\n objectFit=\"contain\"\n />\n </div>\n <h2 style=\"margin: 0;\">{{ currentItem()?.name || \"\" }}</h2>\n <p style=\"color: #ffd700; font-weight: bold; margin: 8px 0;\">{{ currentItem()?.price ?? 0 }} {{ goldTerm }}</p>\n @if (currentItem()?.quantity !== undefined) {\n <div class=\"rpg-shop-details-qty\">{t(\"rpg.shop.qty\")}: x{{ currentItem()?.quantity }}</div>\n }\n </div>\n <div>\n @if (currentItem()?.equipped) {\n <div class=\"rpg-shop-equipped\">{t(\"rpg.shop.already-equipped\")}</div>\n }\n </div>\n <div class=\"rpg-shop-details-desc\">\n {{ currentItem()?.description || \"\" }}\n </div>\n <div>\n @if (displayStats().length > 0) {\n <div class=\"rpg-shop-stats\">\n @for ((stat,index) of displayStats) {\n <div class=\"rpg-shop-stat\" class={{positive: stat.delta > 0, negative: stat.delta < 0}}>\n <div class=\"rpg-shop-stat-key\">{{ stat.label }}</div>\n <div class=\"rpg-shop-stat-value\">\n {{ stat.delta > 0 ? '+' : '' }}{{ stat.delta }}\n </div>\n @if (stat.current !== undefined) {\n <div class=\"rpg-shop-stat-current\">{{ stat.current }} → {{ stat.next }}</div>\n }\n </div>\n }\n </div>\n }\n </div>\n <button class=\"rpg-shop-btn\" click={backToMode()}>{t(\"rpg.shop.back\")}</button>\n </div>\n </div>\n </div>\n }\n @if (quantityDialogOpen) {\n <div class=\"rpg-shop-modal\" click={closeQuantityDialogFromPointer}>\n <div class=\"rpg-shop-modal-card\" click={stopEvent}>\n <div class=\"rpg-shop-modal-title\">{{ actionLabel }}</div>\n <div class=\"rpg-shop-modal-item\">{{ currentItem()?.name || \"\" }}</div>\n @if (currentItem()?.quantity !== undefined) {\n <div class=\"rpg-shop-modal-qty\">{t(\"rpg.shop.available\")}: x{{ currentItem()?.quantity }}</div>\n }\n <div class=\"rpg-shop-quantity\">\n <div class=\"rpg-shop-quantity-label\">{t(\"rpg.shop.quantity\")}</div>\n <div class=\"rpg-shop-quantity-controls\">\n <button class=\"rpg-shop-btn\" click={changeQuantity(-1)}>-</button>\n <div class=\"rpg-shop-quantity-value\">{{ quantity }}</div>\n <button class=\"rpg-shop-btn\" click={changeQuantity(1)}>+</button>\n </div>\n </div>\n <div class=\"rpg-shop-modal-total\">\n <span>{t(\"rpg.shop.total\")}</span>\n <span>{{ totalPrice() }} {{ goldTerm }}</span>\n </div>\n <div class=\"rpg-shop-modal-actions\">\n <button class=\"rpg-shop-btn rpg-shop-btn-secondary\" click={closeQuantityDialog()}>{t(\"rpg.menu.cancel\")}</button>\n <button class=\"rpg-shop-btn\" click={confirmTrade()}>\n {{ actionLabel() }} x{{ quantity() }}\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </DOMContainer>\n\n<script>\n import { mount, signal, computed, createTabindexNavigator, effect } from \"canvasengine\";\n import { inject } from \"../../../core/inject\";\n import { RpgClientEngine } from \"../../../RpgClientEngine\";\n import { getKeyboardControlBind } from \"../../../services/actionInput\";\n\n const engine = inject(RpgClientEngine)\n const { t } = engine.i18n()\n const currentPlayer = engine.scene.currentPlayer\n const keyboardControls = engine.globalConfig.keyboardControls\n const iconSheet = (iconId) => ({\n definition: engine.getSpriteSheet(iconId),\n playing: \"default\"\n })\n const goldTerm = engine.globalConfig.goldTerm || 'G'\n\n const selectedItem = signal(0)\n const selectedTab = signal(0)\n const tradeMode = signal('buy')\n const tradeView = signal('mode')\n const selectedModeIndex = signal(0)\n const quantity = signal(1)\n const quantityDialogOpen = signal(false)\n const defaultMessage = t(\"rpg.shop.default-message\")\n const tabs = [\n { id: 'item', label: t(\"rpg.menu.items\") },\n { id: 'weapon', label: t(\"rpg.menu.weapons\") },\n { id: 'armor', label: t(\"rpg.menu.armor\") }\n ]\n\n const { data, onInteraction , onFinish } = defineProps()\n\n const resolveProp = (value) => typeof value === \"function\" ? value() : value\n const guiData = computed(() => resolveProp(data) || {})\n const shopMessage = computed(() => {\n const message = resolveProp(guiData().message)\n return message ? String(message) : defaultMessage\n })\n const face = computed(() => resolveProp(guiData().face))\n const hasFace = computed(() => {\n const value = face()\n return value && value.id\n })\n const buyItems = computed(() => guiData().items || [])\n const sellItems = computed(() => guiData().sellItems || [])\n const activeItems = computed(() => tradeMode() === 'buy' ? buyItems() : sellItems())\n const filteredItems = computed(() => {\n const tab = tabs[selectedTab()]\n const items = activeItems()\n if (!tab) return []\n return items.filter((item) => item?.type === tab.id)\n })\n const currentItem = computed(() => filteredItems()[selectedItem()])\n const gold = computed(() => currentPlayer()._gold())\n const actionLabel = computed(() => tradeMode() === 'buy' ? t(\"rpg.shop.buy\") : t(\"rpg.shop.sell\"))\n const faceSheet = (graphicId, animationName) => ({\n definition: engine.getSpriteSheet(graphicId),\n playing: animationName || \"default\"\n })\n const maxQuantity = computed(() => {\n const item = currentItem()\n if (!item) return 0\n const price = item?.price || 0\n if (price <= 0) return 0\n if (tradeMode() === 'sell') {\n const qty = item?.quantity ?? 0\n return Math.max(0, qty)\n }\n return Math.max(1, Math.floor(gold() / price))\n })\n const totalPrice = computed(() => {\n const price = currentItem()?.price || 0\n return price * quantity()\n })\n const displayStats = computed(() => {\n const stats = currentItem()?.stats || {}\n const params = guiData().playerParams || {}\n const order = ['atk', 'def', 'pdef', 'sdef', 'str', 'dex', 'int', 'agi', 'maxHp', 'maxSp']\n const labels = {\n atk: 'ATK',\n def: 'DEF',\n pdef: 'PDEF',\n sdef: 'SDEF',\n str: 'STR',\n dex: 'DEX',\n int: 'INT',\n agi: 'AGI',\n maxHp: 'MAX HP',\n maxSp: 'MAX SP'\n }\n const orderedKeys = order.filter((key) => stats[key] !== undefined)\n const extraKeys = Object.keys(stats).filter((key) => !order.includes(key))\n const keys = orderedKeys.concat(extraKeys)\n const list = []\n for (const key of keys) {\n const delta = stats[key]\n if (delta === undefined || delta === 0) continue\n let current = params[key]\n if (current === undefined && key === 'def') current = params.pdef\n const next = current !== undefined ? current + delta : undefined\n list.push({\n key,\n label: labels[key] || key.toUpperCase(),\n delta,\n current,\n next\n })\n }\n return list\n })\n const nav = createTabindexNavigator(selectedItem, { count: () => filteredItems().length }, 'wrap')\n const navTab = createTabindexNavigator(selectedTab, { count: () => tabs.length }, 'wrap')\n const navMode = createTabindexNavigator(selectedModeIndex, { count: () => 2 }, 'wrap')\n\n function selectItem(index) {\n return function() {\n selectedItem.set(index)\n quantity.set(1)\n if (!isItemDisabled(filteredItems()[index])) {\n quantityDialogOpen.set(true)\n }\n }\n }\n\n function selectTab(index) {\n return function() {\n selectedTab.set(index)\n selectedItem.set(0)\n }\n }\n\n function selectMode(mode) {\n return function() {\n tradeMode.set(mode)\n selectedModeIndex.set(mode === 'buy' ? 0 : 1)\n selectedItem.set(0)\n quantity.set(1)\n tradeView.set('items')\n }\n }\n\n function isItemDisabled(item) {\n if (!item) return true\n const price = item?.price || 0\n if (price <= 0) return true\n if (tradeMode() === 'sell') {\n const qty = item?.quantity ?? 0\n return qty <= 0\n }\n return gold() < price\n }\n\n function backToMode() {\n return function() {\n tradeView.set('mode')\n }\n }\n\n function changeQuantity(delta) {\n return function() {\n const limit = maxQuantity()\n if (limit <= 0) return\n const nextValue = Math.max(1, Math.min(limit, quantity() + delta))\n if (nextValue !== quantity()) {\n quantity.set(nextValue)\n }\n }\n }\n\n function closeQuantityDialog() {\n return function() {\n quantityDialogOpen.set(false)\n }\n }\n\n const stopEvent = (event) => {\n event?.stopPropagation?.()\n }\n\n const closeQuantityDialogFromPointer = (event) => {\n stopEvent(event)\n quantityDialogOpen.set(false)\n }\n\n const closeShop = () => {\n if (quantityDialogOpen()) {\n quantityDialogOpen.set(false)\n return\n }\n onFinish()\n }\n\n const closeShopFromPointer = (event) => {\n stopEvent(event)\n closeShop()\n }\n\n function confirmTrade() {\n return function() {\n const item = currentItem()\n if (!item || isItemDisabled(item)) {\n quantityDialogOpen.set(false)\n return\n }\n const action = tradeMode() === 'buy' ? 'buyItem' : 'sellItem'\n onInteraction(action, { id: item.id, nb: quantity() })\n quantityDialogOpen.set(false)\n }\n }\n\n effect(() => {\n const count = filteredItems().length\n if (selectedItem() >= count) {\n selectedItem.set(Math.max(0, count - 1))\n }\n })\n\n const modeControls = signal({\n left: {\n repeat: true,\n bind: keyboardControls.left,\n throttle: 150,\n keyDown() {\n navMode.next(-1)\n }\n },\n right: {\n repeat: true,\n bind: keyboardControls.right,\n throttle: 150,\n keyDown() {\n navMode.next(1)\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n const mode = selectedModeIndex() === 0 ? 'buy' : 'sell'\n tradeMode.set(mode)\n selectedItem.set(0)\n quantity.set(1)\n tradeView.set('items')\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n onFinish()\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n const itemControls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n if (quantityDialogOpen()) {\n changeQuantity(1)()\n return\n }\n nav.next(-1)\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n if (quantityDialogOpen()) {\n changeQuantity(-1)()\n return\n }\n nav.next(1)\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (quantityDialogOpen()) {\n const item = currentItem()\n if (!item || isItemDisabled(item)) {\n quantityDialogOpen.set(false)\n return\n }\n const action = tradeMode() === 'buy' ? 'buyItem' : 'sellItem'\n onInteraction(action, { id: item.id, nb: quantity() })\n quantityDialogOpen.set(false)\n return\n }\n const item = currentItem()\n if (!isItemDisabled(item)) {\n quantityDialogOpen.set(true)\n }\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (quantityDialogOpen()) {\n quantityDialogOpen.set(false)\n return\n }\n tradeView.set('mode')\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n const tabControls = signal({\n left: {\n repeat: true,\n bind: keyboardControls.left,\n throttle: 150,\n keyDown() {\n if (quantityDialogOpen()) return\n navTab.next(-1)\n }\n },\n right: {\n repeat: true,\n bind: keyboardControls.right,\n throttle: 150,\n keyDown() {\n if (quantityDialogOpen()) return\n navTab.next(1)\n }\n },\n gamepad: {\n enabled: true\n }\n })\n</script>\n"],"mappings":";;;;;AAYM,SAAS,UAAU,SAAS;CACX,SAAS,OAAI;CAC5B,MAAM,cAAc,eAAO,OAAA;CACP,eAAK,OAAA;CACzB,MAAM,SAAS,OAAC,eAAA;CACxB,MAAM,EAAE,MAAM,OAAO,KAAI;CACzB,MAAM,gBAAe,OAAI,MAAU;CACnC,MAAM,mBAAmB,OAAK,aAAe;CAC7C,MAAM,aAAa,YAAM;EACrB,YAAY,OAAK,eAAA,MAAA;EACjB,SAAS;CACb;CACA,MAAM,WAAW,OAAI,aAAA,YAAA;CACrB,MAAM,eAAW,OAAA,CAAA;;CAEjB,MAAM,YAAW,OAAO,KAAI;CAC5B,MAAM,YAAW,OAAI,MAAU;CAC/B,MAAM,oBAAe,OAAY,CAAC;CAClC,MAAM,WAAW,OAAO,CAAC;CACzB,MAAM,qBAAmB,OAAS,KAAK;CACvC,MAAM,iBAAiB,EAAE,0BAAwB;CACjD,MAAM,OAAO;EACT;GAAE,IAAI;GAAQ,OAAO,EAAE,gBAAY;EAAM;EACzC;GAAE,IAAI;GAAU,OAAM,EAAG,kBAAA;EAAA;EACzB;GAAE,IAAI;GAAS,OAAM,EAAG,gBAAgB;EAAC;CAC7C;CACA,MAAM,EAAE,MAAM,eAAe,aAAa,YAAW;CACrD,MAAM,eAAe,UAAU,OAAM,UAAA,aAAA,MAAA,IAAA;CACrC,MAAM,UAAU,eAAe,YAAS,IAAO,KAAI,CAAA,CAAA;CACnD,MAAM,cAAc,eAAe;EAC/B,MAAM,UAAU,YAAY,QAAQ,EAAA,OAAO;EAC3C,OAAO,UAAU,OAAO,OAAO,IAAI;CACvC,CAAC;CACD,MAAM,OAAO,eAAe,YAAY,QAAO,EAAG,IAAC,CAAI;CACvD,MAAM,UAAU,eAAe;EAC3B,MAAM,QAAQ,KAAK;EACnB,OAAO,SAAS,MAAM;CAC1B,CAAC;CACD,MAAM,WAAW,eAAa,QAAU,EAAA,SAAA,CAAA,CAAA;CACxC,MAAM,YAAY,eAAW,QAAA,EAAA,aAAA,CAAA,CAAA;CAC7B,MAAM,cAAc,eAAS,UAAA,MAAA,QAAA,SAAA,IAAA,UAAA,CAAA;CAC7B,MAAM,gBAAgB,eAAG;EACrB,MAAM,MAAM,KAAA,YAAA;EACZ,MAAM,QAAO,YAAK;EAClB,IAAI,CAAC,KACD,OAAO,CAAC;EACZ,OAAO,MAAM,QAAQ,SAAS,MAAM,SAAS,IAAC,EAAA;CAClD,CAAC;CACD,MAAM,cAAc,eAAa,cAAG,EAAA,aAAA,EAAA;CACpC,MAAM,OAAO,eAAe,cAAc,EAAC,MAAI,CAAI;CACnD,MAAM,cAAc,eAAe,UAAS,MAAO,QAAC,EAAA,cAAuB,IAAE,EAAA,eAAA,CAAA;CAC7E,MAAM,aAAa,WAAW,mBAAgB;EAC1C,YAAY,OAAO,eAAa,SAAO;EACvC,SAAS,iBAAiB;CAC9B;CACA,MAAM,cAAc,eAAS;EACzB,MAAM,OAAO,YAAK;aAEd,OAAO;EACX,MAAM,QAAQ,MAAM,SAAK;EACzB,IAAI,SAAS,GACT,OAAO;EACX,IAAI,UAAU,MAAM,QAAQ;GACxB,MAAM,MAAM,MAAM,YAAY;GAC9B,OAAO,KAAK,IAAI,GAAG,GAAG;EAC1B;EACA,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC;CACjD,CAAC;CACD,MAAM,aAAa,eAAe;EAE9B,QADc,YAAY,GAAG,SAAS,KACvB,SAAS;CAC5B,CAAC;CACD,MAAM,eAAe,eAAe;EAChC,MAAM,QAAQ,YAAY,GAAG,SAAS,CAAA;EACtC,MAAM,SAAS,QAAQ,EAAE,gBAAgB,CAAA;EACzC,MAAM,QAAQ;GAAC;GAAO;GAAO;GAAQ;GAAI;GAAW;GAAK;GAAK;GAAU;GAAU;EAAO;EACzF,MAAM,SAAS;GACX,KAAK;GACL,KAAK;GACL,MAAM;GACN,MAAM;GACN,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,OAAO;;EAEX;EACA,MAAM,cAAc,MAAK,QAAS,QAAM,MAAK,SAAQ,KAAA,CAAO;EAC5D,MAAM,YAAY,OAAO,KAAI,KAAI,EAAA,QAAW,QAAK,CAAA,MAAQ,SAAK,GAAA,CAAA;EAC9D,MAAM,OAAO,YAAY,OAAO,SAAC;EACjC,MAAM,OAAO,CAAC;EACd,KAAK,MAAM,OAAO,MAAM;GACpB,MAAM,QAAQ,MAAM;GACpB,IAAI,UAAU,KAAA,KAAa,UAAK,GAC5B;GACJ,IAAI,UAAU,OAAO;GACrB,IAAI,YAAY,KAAA,KAAa,QAAA,OACzB,UAAU,OAAO;GACrB,MAAM,OAAO,YAAY,KAAA,IAAS,UAAQ,QAAa,KAAA;GACvD,KAAK,KAAK;IACN;IACA,OAAO,OAAO,QAAM,IAAA,YAAA;IACpB;IACA;IACA;GACJ,CAAC;EACL;EACA,OAAO;CACX,CAAC;CACD,MAAM,MAAM,wBAAuB,cAAe,EAAA,aAAe,cAAI,EAAA,OAAA,GAAA,MAAA;CACrE,MAAM,SAAS,wBAAkB,aAAA,EAAA,aAAA,KAAA,OAAA,GAAA,MAAA;CACjC,MAAM,UAAU,wBAAgB,mBAAA,EAAA,aAAA,EAAA,GAAA,MAAA;CAChC,SAAS,WAAW,OAAO;EACvB,OAAO,WAAY;GACf,aAAa,IAAI,KAAK;GACtB,SAAS,IAAI,CAAC;GACd,IAAI,CAAC,eAAe,cAAc,EAAE,MAAK,GACrC,mBAAmB,IAAI,IAAI;EAEnC;CACJ;CACA,SAAS,UAAU,OAAO;EACtB,OAAO,WAAY;GACf,YAAY,IAAI,KAAK;GACrB,aAAa,IAAI,CAAC;EACtB;CACJ;CACA,SAAS,WAAW,MAAM;EACtB,OAAO,WAAY;GACf,UAAU,IAAI,IAAI;GAClB,kBAAiB,IAAA,SAAA,QAAA,IAAA,CAAA;GACjB,aAAa,IAAI,CAAA;GACjB,SAAQ,IAAA,CAAA;GACR,UAAS,IAAI,OAAA;EACjB;CACJ;CACA,SAAS,eAAe,MAAK;EACzB,IAAI,CAAC,MACD,OAAO;EACX,MAAM,QAAQ,MAAM,SAAS;EAC7B,IAAI,SAAS,GACT,OAAO;EACX,IAAI,UAAU,MAAM,QAEhB,QADY,MAAM,YAAW,MACf;EAElB,OAAO,KAAK,IAAI;CACpB;CACA,SAAS,aAAa;EAClB,OAAO,WAAY;GACf,UAAU,IAAI,MAAM;EACxB;CACJ;CACA,SAAS,eAAe,OAAK;EACzB,OAAO,WAAY;GACf,MAAM,QAAQ,YAAW;GACzB,IAAI,SAAS,GACT;GACJ,MAAM,YAAY,KAAI,IAAG,GAAA,KAAA,IAAA,OAAA,SAAA,IAAA,KAAA,CAAA;GACzB,IAAI,cAAc,SAAG,GACjB,SAAS,IAAI,SAAA;EAErB;CACJ;CACA,SAAS,sBAAI;EACT,OAAM,WAAG;GACP,mBAAY,IAAA,KAAA;;CAElB;CACA,MAAI,aAAe,UAAS;EACxB,OAAO,kBAAkB;CAC7B;CACA,MAAI,kCAAkC,UAAY;;EAE9C,mBAAe,IAAO,KAAA;CAC1B;CACA,MAAI,kBAAoB;EACpB,IAAA,mBAAuB,GAAE;GACzB,mBAAmB,IAAQ,KAAI;GAC3B;EACJ;EACA,SAAC;CACL;;EAEI,UAAM,KAAA;EACN,UAAM;CACV;CACA,SAAS,eAAa;EAClB,OAAM,WAAA;GACN,MAAM,OAAW,YAAQ;GACzB,IAAM,CAAA,QAAA,eAAqB,IAAO,GAAK;IACjC,mBAAoB,IAAI,KAAK;IAC7B;GACF;GAEA,cADe,UAAU,MAAK,QAAK,YAAW,YACxB;IAAE,IAAI,KAAK;IAAC,IAAO,SAAC;GAAA,CAAA;GAC9C,mBAAA,IAAA,KAAA;;CAEJ;;EAEI,MAAM,QAAA,cAAsB,EAAE;EAC9B,IAAA,aAAgB,KAAA,OAChB,aAAiB,IAAG,KAAA,IAAU,GAAG,QAAE,CAAA,CAAA;CAEvC,CAAC;CACD,MAAK,eAAA,OAAA;EACD,MAAM;GACN,QAAM;GACF,MAAM,iBAAa;GACnB,UAAO;GACV,UAAA;IACK,QAAU,KAAC,EAAA;GACjB;EACA;EACA,OAAM;GACF,QAAM;GACN,MAAM,iBAAQ;GACd,UAAU;GACV,UAAO;IACV,QAAA,KAAA,CAAA;GACD;EACA;EACA,QAAM;GACN,MAAM,uBAAwB,iBAAmB,MAAA;GAC7C,UAAU;IACV,MAAS,OAAA,kBAAyB,MAAA,IAAA,QAAA;IACrC,UAAA,IAAA,IAAA;IACK,aAAc,IAAA,CAAA;IAChB,SAAa,IAAA,CAAA;IACT,UAAO,IAAO,OAAA;GAClB;EACJ;EACA,QAAQ;GACJ,MAAI,iBAAkB;GACtB,UAAU;IACV,SAAA;GACA;EACJ;EACA,SAAM,EACF,SAAM,KACV;CACJ,CAAC;CACD,MAAI,eAAM,OAAe;EACrB,IAAI;GACA,QAAM;GACN,MAAM,iBAAiB;GACvB,UAAM;GACN,UAAU;IACN,IAAI,mBAAM,GAAA;KACN,eAAQ,CAAA,EAAA;KACR;IACJ;IACA,IAAI,KAAK,EAAC;GACd;EACJ;EACA,MAAM;GACF,QAAI;GACJ,MAAA,iBAAA;GACA,UAAM;GACN,UAAM;IACN,IAAM,mBAAmB,GAAA;KACnB,eAAQ,EAAA,EAAA;KACT;IACD;IACA,IAAI,KAAK,CAAC;GACd;EACJ;EACA,QAAQ;GACJ,MAAI,uBAAU,iBAAA,MAAA;GACd,UAAQ;IACJ,IAAI,mBAAmB,GAAG;KACtB,MAAK,OAAA,YAAA;KACL,IAAA,CAAA,QAAO,eAAA,IAAA,GAAA;MACP,mBAAA,IAAA,KAAA;MACH;KACL;KAEH,cADU,UAAA,MAAA,QAAA,YAAA,YACV;MAAA,IAAA,KAAA;MAAA,IAAA,SAAA;KAAA,CAAA;KACW,mBAAA,IAAuB,KAAC;KACxB;IACN;IAEE,IAAC,CAAA,eAAA,YAAkB,CAAA,GACjB,mBAAW,IAAA,IAAA;GAEjB;EACJ;EACA,QAAQ;GACJ,MAAA,iBAAA;GACD,UAAA;IACH,IAAA,mBAAA,GAAA;;KAES;IACL;IACI,UAAA,IAAY,MAAI;GACpB;EACJ;EACA,SAAA,EAAA,SAAA,KAEA;CACJ,CAAC;CACD,MAAM,cAAM,OAAc;EACtB,MAAM;GACF,QAAI;GACJ,MAAI,iBAAc;GAClB,UAAI;GACJ,UAAA;IACJ,IAAA,mBAAA,GAAA;IAEQ,OAAC,KAAA,EAAA;GACL;EACJ;EACA,OAAO;GACH,QAAI;GACJ,MAAI,iBAAkB;GACtB,UAAU;GACV,UAAA;IACA,IAAO,mBAAS,GACpB;;GAEA;EACA;EACA,SAAQ,EACJ,SAAA,KACJ;;CAGI,OADK,EAAA,cAAsB;EAAA,OAAA;EAAA,QAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA;GAAA,OAAA;EAAA;CAAA,GAAA,CAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA;GAAA,MAAA;GAAA,OAAA;GAAA,cAAA;GAAA,OAAA;EAAA;EAAA,aAAA;CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA;GAAA,OAAA;EAAA;CAAA,GAAA,CAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,kBAAA;CAAA,GAAA,CAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,oBAAA;CAAA,GAAA,CAAA,EAAA,YAAA,EAAA,SAAA,MAAA,GAAA,KAAA,eAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,2BAAA;CAAA,GAAA,EAAA,WAAA;EAAA,OAAA,eAAA,UAAA,KAAA,EAAA,IAAA,KAAA,EAAA,UAAA,CAAA;EAAA,OAAA;EAAA,QAAA;EAAA,WAAA;CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,yBAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,aAAA,eAAA,YAAA,CAAA;CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,gBAAA;EAAA,aAAA,eAAA,KAAA,IAAA,QAAA;CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,gBAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,gBAAA;CAAA,GAAA,CAAA,KAAA,eAAA,UAAA,MAAA,MAAA,SAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,yCAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,yCAAA;CAAA,GAAA,CAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,0BAAA;CAAA,GAAA,CAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,wBAAA;EAAA,aAAA;CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,aAAA;EAAA,aAAA,eAAA,EAAA,wBAAA,CAAA;CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,iBAAA;CAAA,GAAA,EAAA,YAAA;EAAA,UAAA;EAAA,UAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,oCAAA;CAAA,GAAA,CAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA,CAAA,gBAAA,gBAAA,EAAA,QAAA,kBAAA,MAAA,EAAA,EAAA,CAAA;GAAA,OAAA,WAAA,KAAA;EAAA;EAAA,aAAA,eAAA,EAAA,cAAA,CAAA;CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA,CAAA,gBAAA,gBAAA,EAAA,QAAA,kBAAA,MAAA,EAAA,EAAA,CAAA;GAAA,OAAA,WAAA,MAAA;EAAA;EAAA,aAAA,eAAA,EAAA,eAAA,CAAA;CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,SAAA,EAAA,YAAA,EAAA,SAAA,MAAA,GAAA,CAAA,EAAA,YAAA;EAAA,UAAA;EAAA,UAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,gBAAA;CAAA,GAAA,KAAA,OAAA,KAAA,UAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA,CAAA,gBAAA,gBAAA,EAAA,QAAA,YAAA,MAAA,MAAA,EAAA,CAAA;GAAA,UAAA;GAAA,OAAA,UAAA,KAAA;EAAA;EAAA,aAAA,IAAA;CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,mBAAA;CAAA,GAAA,CAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,gBAAA;CAAA,GAAA,EAAA,YAAA;EAAA,UAAA;EAAA,UAAA;CAAA,GAAA,KAAA,gBAAA,MAAA,UAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA,CAAA,iBAAA,gBAAA;IAAA,UAAA,eAAA,IAAA;IAAA,UAAA,aAAA,MAAA;GAAA,EAAA,CAAA;GAAA,UAAA;GAAA,OAAA,WAAA,KAAA;EAAA;CAAA,GAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,qBAAA;EAAA,GAAA,KAAA,KAAA,YAAA,EAAA,WAAA;GAAA,OAAA,eAAA,UAAA,KAAA,IAAA,CAAA;GAAA,SAAA;GAAA,OAAA;GAAA,QAAA;GAAA,WAAA;EAAA,CAAA,CAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,qBAAA;GAAA,aAAA,KAAA;EAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,sBAAA;GAAA,aAAA,KAAA,QAAA;EAAA,CAAA;EAAA,KAAA,eAAA,KAAA,aAAA,KAAA,CAAA,SAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,oBAAA;GAAA,aAAA,MAAA,KAAA;EAAA,CAAA,CAAA;EAAA,KAAA,KAAA,gBAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,oBAAA;GAAA,aAAA,eAAA,EAAA,mBAAA,CAAA;EAAA,CAAA,CAAA;CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,mBAAA;CAAA,GAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,0BAAA;EAAA,GAAA;GAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,wBAAA;GAAA,GAAA,EAAA,WAAA;IAAA,OAAA,eAAA,UAAA,YAAA,GAAA,IAAA,CAAA;IAAA,SAAA;IAAA,OAAA;IAAA,QAAA;IAAA,WAAA;GAAA,CAAA,CAAA;GAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,aAAA;IAAA,aAAA,eAAA,YAAA,GAAA,QAAA,EAAA;GAAA,CAAA;GAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,oDAAA;IAAA,aAAA,eAAA,YAAA,GAAA,SAAA,IAAA,QAAA;GAAA,CAAA;GAAA,KAAA,eAAA,YAAA,GAAA,aAAA,KAAA,CAAA,SAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,uBAAA;IAAA,aAAA,eAAA,EAAA,cAAA,IAAA,QAAA,YAAA,GAAA,QAAA;GAAA,CAAA,CAAA;EAAA,CAAA;EAAA,EAAA,YAAA,EAAA,SAAA,MAAA,GAAA,KAAA,eAAA,YAAA,GAAA,QAAA,SAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,oBAAA;GAAA,aAAA,eAAA,EAAA,2BAAA,CAAA;EAAA,CAAA,CAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,wBAAA;GAAA,aAAA,eAAA,YAAA,GAAA,eAAA,EAAA;EAAA,CAAA;EAAA,EAAA,YAAA,EAAA,SAAA,MAAA,GAAA,KAAA,eAAA,aAAA,EAAA,SAAA,CAAA,SAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,iBAAA;EAAA,GAAA,KAAA,eAAA,MAAA,UAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,CAAA,iBAAA;IAAA,UAAA,KAAA,QAAA;IAAA,UAAA,KAAA,QAAA;GAAA,CAAA,EAAA;EAAA,GAAA;GAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,oBAAA;IAAA,aAAA,KAAA;GAAA,CAAA;GAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,sBAAA;IAAA,aAAA,KAAA,QAAA,IAAA,MAAA,KAAA,KAAA;GAAA,CAAA;GAAA,KAAA,eAAA,KAAA,YAAA,KAAA,CAAA,SAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,wBAAA;IAAA,aAAA,KAAA,UAAA,QAAA,KAAA;GAAA,CAAA,CAAA;EAAA,CAAA,CAAA,CAAA,CAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA;IAAA,OAAA;IAAA,OAAA,WAAA;GAAA;GAAA,aAAA,eAAA,EAAA,eAAA,CAAA;EAAA,CAAA;CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,KAAA,0BAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA;GAAA,OAAA;EAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA;GAAA,OAAA;GAAA,OAAA;EAAA;CAAA,GAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,uBAAA;GAAA,aAAA;EAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,sBAAA;GAAA,aAAA,eAAA,YAAA,GAAA,QAAA,EAAA;EAAA,CAAA;EAAA,KAAA,eAAA,YAAA,GAAA,aAAA,KAAA,CAAA,SAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,qBAAA;GAAA,aAAA,eAAA,EAAA,oBAAA,IAAA,QAAA,YAAA,GAAA,QAAA;EAAA,CAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,oBAAA;EAAA,GAAA,CAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,0BAAA;GAAA,aAAA,eAAA,EAAA,mBAAA,CAAA;EAAA,CAAA,GAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,6BAAA;EAAA,GAAA;GAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA;KAAA,OAAA;KAAA,OAAA,eAAA,EAAA;IAAA;IAAA,aAAA;GAAA,CAAA;GAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA,EAAA,OAAA,0BAAA;IAAA,aAAA;GAAA,CAAA;GAAA,EAAA,YAAA;IAAA,SAAA;IAAA,OAAA;KAAA,OAAA;KAAA,OAAA,eAAA,CAAA;IAAA;IAAA,aAAA;GAAA,CAAA;EAAA,CAAA,CAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,uBAAA;EAAA,GAAA,CAAA,EAAA,YAAA;GAAA,SAAA;GAAA,aAAA,eAAA,EAAA,gBAAA,CAAA;EAAA,CAAA,GAAA,EAAA,YAAA;GAAA,SAAA;GAAA,aAAA,eAAA,WAAA,IAAA,QAAA;EAAA,CAAA,CAAA,CAAA;EAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA,EAAA,OAAA,yBAAA;EAAA,GAAA,CAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA;IAAA,OAAA;IAAA,OAAA,oBAAA;GAAA;GAAA,aAAA,eAAA,EAAA,iBAAA,CAAA;EAAA,CAAA,GAAA,EAAA,YAAA;GAAA,SAAA;GAAA,OAAA;IAAA,OAAA;IAAA,OAAA,aAAA;GAAA;GAAA,aAAA,eAAA,YAAA,IAAA,OAAA,SAAA,CAAA;EAAA,CAAA,CAAA,CAAA;CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACpB;AACT;AAEA,IAAM,iBAAiB"}
@@ -13,6 +13,9 @@ declare class BridgeWebsocket extends AbstractWebsocket {
13
13
  private room;
14
14
  private socket;
15
15
  private socketRoom?;
16
+ private roomId;
17
+ private query?;
18
+ private readonly privateId;
16
19
  private listeners;
17
20
  private rooms;
18
21
  private serverInstance;
@@ -38,7 +41,7 @@ declare class BridgeWebsocket extends AbstractWebsocket {
38
41
  * await websocket.reconnect()
39
42
  * ```
40
43
  */
41
- updateProperties(_params: SocketUpdateProperties): void;
44
+ updateProperties({ room, query }: SocketUpdateProperties): void;
42
45
  /**
43
46
  * Reconnect the client to the current Party room
44
47
  *
@@ -57,6 +60,8 @@ declare class BridgeWebsocket extends AbstractWebsocket {
57
60
  * ```
58
61
  */
59
62
  reconnect(listeners?: (data: any) => void): Promise<void>;
63
+ private connectToRoom;
64
+ private normalizeQuery;
60
65
  private detachCurrentSocket;
61
66
  getServer(): any;
62
67
  getSocket(): any;
@@ -13,14 +13,15 @@ var BridgeWebsocket = class extends AbstractWebsocket {
13
13
  this.context = context;
14
14
  this.server = server;
15
15
  this.mode = "standalone";
16
+ this.roomId = "lobby-1";
17
+ this.privateId = "player-client-id";
16
18
  this.listeners = [];
17
19
  this.rooms = {
18
20
  partyFn: async (roomId) => {
19
- this.room = new ServerIo(roomId, this.rooms);
20
- const server = new this.server(this.room);
21
+ const room = new ServerIo(roomId, this.rooms);
22
+ const server = new this.server(room);
21
23
  await server.onStart();
22
24
  await server.subRoom.onStart();
23
- this.context.set("server", server);
24
25
  return server;
25
26
  },
26
27
  env: {}
@@ -37,20 +38,8 @@ var BridgeWebsocket = class extends AbstractWebsocket {
37
38
  }
38
39
  async _connection(listeners) {
39
40
  this.detachCurrentSocket();
40
- this.serverInstance = this.context.get("server");
41
- this.socket = new ClientIo(this.serverInstance, "player-client-id");
42
- const url = new URL("http://localhost");
43
- const request = new Request(url.toString(), {
44
- method: "GET",
45
- headers: { "Content-Type": "application/json" }
46
- });
41
+ await this.connectToRoom();
47
42
  listeners?.(this.socket);
48
- this.room.clients.set(this.socket.id, this.socket);
49
- this.socketRoom = this.room;
50
- this.listeners.forEach(({ handler }) => {
51
- this.socket.addEventListener("message", handler);
52
- });
53
- await this.serverInstance.onConnect(this.socket.conn, { request });
54
43
  return this.socket;
55
44
  }
56
45
  on(key, callback) {
@@ -99,7 +88,10 @@ var BridgeWebsocket = class extends AbstractWebsocket {
99
88
  * await websocket.reconnect()
100
89
  * ```
101
90
  */
102
- updateProperties(_params) {}
91
+ updateProperties({ room, query }) {
92
+ this.roomId = room;
93
+ this.query = query;
94
+ }
103
95
  /**
104
96
  * Reconnect the client to the current Party room
105
97
  *
@@ -122,6 +114,32 @@ var BridgeWebsocket = class extends AbstractWebsocket {
122
114
  listeners?.(socket);
123
115
  });
124
116
  }
117
+ async connectToRoom() {
118
+ if (this.serverInstance?.room?.id !== this.roomId) {
119
+ const party = await this.room.context.parties.main.get(this.roomId);
120
+ this.serverInstance = party.server;
121
+ this.context.set("server", this.serverInstance);
122
+ this.room = this.serverInstance.room;
123
+ } else this.serverInstance = this.context.get("server");
124
+ this.socket = new ClientIo(this.serverInstance, this.privateId);
125
+ const url = new URL("http://localhost");
126
+ const query = this.normalizeQuery(this.query);
127
+ if (query) for (const [key, value] of Object.entries(query)) url.searchParams.set(key, value);
128
+ const request = new Request(url.toString(), {
129
+ method: "GET",
130
+ headers: { "Content-Type": "application/json" }
131
+ });
132
+ this.room.clients.set(this.socket.id, this.socket);
133
+ this.socketRoom = this.room;
134
+ this.listeners.forEach(({ handler }) => {
135
+ this.socket.addEventListener("message", handler);
136
+ });
137
+ await this.serverInstance.onConnect(this.socket.conn, { request });
138
+ }
139
+ normalizeQuery(query) {
140
+ if (!query) return;
141
+ return Object.fromEntries(Object.entries(query).filter((entry) => typeof entry[1] === "string"));
142
+ }
125
143
  detachCurrentSocket() {
126
144
  if (!this.socket) return;
127
145
  this.listeners.forEach(({ handler }) => {