@rpgjs/client 5.0.0-alpha.9 → 5.0.0-beta.10

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 (347) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +19 -0
  3. package/dist/Game/AnimationManager.d.ts +8 -0
  4. package/dist/Game/AnimationManager.js +35 -0
  5. package/dist/Game/AnimationManager.js.map +1 -0
  6. package/dist/Game/AnimationManager.spec.d.ts +1 -0
  7. package/dist/Game/Event.d.ts +1 -1
  8. package/dist/Game/Event.js +12 -0
  9. package/dist/Game/Event.js.map +1 -0
  10. package/dist/Game/Map.d.ts +31 -2
  11. package/dist/Game/Map.js +138 -0
  12. package/dist/Game/Map.js.map +1 -0
  13. package/dist/Game/Object.d.ts +189 -0
  14. package/dist/Game/Object.js +255 -0
  15. package/dist/Game/Object.js.map +1 -0
  16. package/dist/Game/Player.d.ts +1 -1
  17. package/dist/Game/Player.js +12 -0
  18. package/dist/Game/Player.js.map +1 -0
  19. package/dist/Gui/Gui.d.ts +192 -7
  20. package/dist/Gui/Gui.js +475 -0
  21. package/dist/Gui/Gui.js.map +1 -0
  22. package/dist/Gui/Gui.spec.d.ts +1 -0
  23. package/dist/Gui/NotificationManager.d.ts +23 -0
  24. package/dist/Gui/NotificationManager.js +49 -0
  25. package/dist/Gui/NotificationManager.js.map +1 -0
  26. package/dist/Resource.d.ts +97 -0
  27. package/dist/Resource.js +133 -0
  28. package/dist/Resource.js.map +1 -0
  29. package/dist/RpgClient.d.ts +295 -13
  30. package/dist/RpgClientEngine.d.ts +671 -15
  31. package/dist/RpgClientEngine.js +1442 -0
  32. package/dist/RpgClientEngine.js.map +1 -0
  33. package/dist/Sound.d.ts +199 -0
  34. package/dist/Sound.js +167 -0
  35. package/dist/Sound.js.map +1 -0
  36. package/dist/_virtual/_@oxc-project_runtime@0.130.0/helpers/decorate.js +9 -0
  37. package/dist/_virtual/_@oxc-project_runtime@0.130.0/helpers/decorateMetadata.js +6 -0
  38. package/dist/components/animations/animation.ce.js +23 -0
  39. package/dist/components/animations/animation.ce.js.map +1 -0
  40. package/dist/components/animations/hit.ce.js +64 -0
  41. package/dist/components/animations/hit.ce.js.map +1 -0
  42. package/dist/components/animations/index.d.ts +4 -0
  43. package/dist/components/animations/index.js +11 -0
  44. package/dist/components/animations/index.js.map +1 -0
  45. package/dist/components/character.ce.js +572 -0
  46. package/dist/components/character.ce.js.map +1 -0
  47. package/dist/components/dynamics/bar.ce.js +96 -0
  48. package/dist/components/dynamics/bar.ce.js.map +1 -0
  49. package/dist/components/dynamics/image.ce.js +23 -0
  50. package/dist/components/dynamics/image.ce.js.map +1 -0
  51. package/dist/components/dynamics/parse-value.d.ts +4 -0
  52. package/dist/components/dynamics/parse-value.js +63 -0
  53. package/dist/components/dynamics/parse-value.js.map +1 -0
  54. package/dist/components/dynamics/parse-value.spec.d.ts +1 -0
  55. package/dist/components/dynamics/shape-utils.d.ts +16 -0
  56. package/dist/components/dynamics/shape-utils.js +73 -0
  57. package/dist/components/dynamics/shape-utils.js.map +1 -0
  58. package/dist/components/dynamics/shape-utils.spec.d.ts +1 -0
  59. package/dist/components/dynamics/shape.ce.js +83 -0
  60. package/dist/components/dynamics/shape.ce.js.map +1 -0
  61. package/dist/components/dynamics/text.ce.js +50 -0
  62. package/dist/components/dynamics/text.ce.js.map +1 -0
  63. package/dist/components/gui/box.ce.js +26 -0
  64. package/dist/components/gui/box.ce.js.map +1 -0
  65. package/dist/components/gui/dialogbox/index.ce.js +198 -0
  66. package/dist/components/gui/dialogbox/index.ce.js.map +1 -0
  67. package/dist/components/gui/gameover.ce.js +169 -0
  68. package/dist/components/gui/gameover.ce.js.map +1 -0
  69. package/dist/components/gui/hud/hud.ce.js +83 -0
  70. package/dist/components/gui/hud/hud.ce.js.map +1 -0
  71. package/dist/components/gui/index.d.ts +15 -3
  72. package/dist/components/gui/index.js +14 -0
  73. package/dist/components/gui/menu/equip-menu.ce.js +427 -0
  74. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -0
  75. package/dist/components/gui/menu/exit-menu.ce.js +55 -0
  76. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -0
  77. package/dist/components/gui/menu/items-menu.ce.js +326 -0
  78. package/dist/components/gui/menu/items-menu.ce.js.map +1 -0
  79. package/dist/components/gui/menu/main-menu.ce.js +399 -0
  80. package/dist/components/gui/menu/main-menu.ce.js.map +1 -0
  81. package/dist/components/gui/menu/options-menu.ce.js +49 -0
  82. package/dist/components/gui/menu/options-menu.ce.js.map +1 -0
  83. package/dist/components/gui/menu/skills-menu.ce.js +102 -0
  84. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -0
  85. package/dist/components/gui/mobile/index.d.ts +8 -0
  86. package/dist/components/gui/mobile/index.js +21 -0
  87. package/dist/components/gui/mobile/index.js.map +1 -0
  88. package/dist/components/gui/mobile/mobile.ce.js +79 -0
  89. package/dist/components/gui/mobile/mobile.ce.js.map +1 -0
  90. package/dist/components/gui/notification/notification.ce.js +62 -0
  91. package/dist/components/gui/notification/notification.ce.js.map +1 -0
  92. package/dist/components/gui/save-load.ce.js +211 -0
  93. package/dist/components/gui/save-load.ce.js.map +1 -0
  94. package/dist/components/gui/shop/shop.ce.js +614 -0
  95. package/dist/components/gui/shop/shop.ce.js.map +1 -0
  96. package/dist/components/gui/title-screen.ce.js +164 -0
  97. package/dist/components/gui/title-screen.ce.js.map +1 -0
  98. package/dist/components/index.d.ts +1 -0
  99. package/dist/components/index.js +4 -0
  100. package/dist/components/player-components-utils.d.ts +67 -0
  101. package/dist/components/player-components-utils.js +162 -0
  102. package/dist/components/player-components-utils.js.map +1 -0
  103. package/dist/components/player-components-utils.spec.d.ts +1 -0
  104. package/dist/components/player-components.ce.js +188 -0
  105. package/dist/components/player-components.ce.js.map +1 -0
  106. package/dist/components/prebuilt/hp-bar.ce.js +113 -0
  107. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -0
  108. package/dist/components/prebuilt/index.d.ts +19 -0
  109. package/dist/components/prebuilt/index.js +2 -0
  110. package/dist/components/prebuilt/light-halo.ce.js +70 -0
  111. package/dist/components/prebuilt/light-halo.ce.js.map +1 -0
  112. package/dist/components/scenes/canvas.ce.js +196 -0
  113. package/dist/components/scenes/canvas.ce.js.map +1 -0
  114. package/dist/components/scenes/draw-map.ce.js +79 -0
  115. package/dist/components/scenes/draw-map.ce.js.map +1 -0
  116. package/dist/components/scenes/event-layer.ce.js +29 -0
  117. package/dist/components/scenes/event-layer.ce.js.map +1 -0
  118. package/dist/core/inject.js +18 -0
  119. package/dist/core/inject.js.map +1 -0
  120. package/dist/core/setup.js +16 -0
  121. package/dist/core/setup.js.map +1 -0
  122. package/dist/decorators/spritesheet.d.ts +1 -0
  123. package/dist/decorators/spritesheet.js +11 -0
  124. package/dist/decorators/spritesheet.js.map +1 -0
  125. package/dist/index.d.ts +16 -1
  126. package/dist/index.js +45 -14
  127. package/dist/module.d.ts +43 -4
  128. package/dist/module.js +179 -0
  129. package/dist/module.js.map +1 -0
  130. package/dist/node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js +167 -0
  131. package/dist/node_modules/.pnpm/@signe_di@3.0.1/node_modules/@signe/di/dist/index.js.map +1 -0
  132. package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js +239 -0
  133. package/dist/node_modules/.pnpm/@signe_reactive@3.0.1/node_modules/@signe/reactive/dist/index.js.map +1 -0
  134. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js +13 -0
  135. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/chunk-EUXUH3YW.js.map +1 -0
  136. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js +696 -0
  137. package/dist/node_modules/.pnpm/@signe_room@3.0.1/node_modules/@signe/room/dist/index.js.map +1 -0
  138. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js +44 -0
  139. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  140. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/index.js +241 -0
  141. package/dist/node_modules/.pnpm/@signe_sync@3.0.1/node_modules/@signe/sync/dist/index.js.map +1 -0
  142. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js +115 -0
  143. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -0
  144. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js +401 -0
  145. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -0
  146. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/index.js +2 -0
  147. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js +3756 -0
  148. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -0
  149. package/dist/presets/animation.d.ts +31 -0
  150. package/dist/presets/animation.js +39 -0
  151. package/dist/presets/animation.js.map +1 -0
  152. package/dist/presets/faceset.d.ts +30 -0
  153. package/dist/presets/faceset.js +51 -0
  154. package/dist/presets/faceset.js.map +1 -0
  155. package/dist/presets/icon.d.ts +20 -0
  156. package/dist/presets/icon.js +15 -0
  157. package/dist/presets/icon.js.map +1 -0
  158. package/dist/presets/index.d.ts +123 -0
  159. package/dist/presets/index.js +17 -0
  160. package/dist/presets/index.js.map +1 -0
  161. package/dist/presets/lpc.d.ts +89 -0
  162. package/dist/presets/lpc.js +98 -0
  163. package/dist/presets/lpc.js.map +1 -0
  164. package/dist/presets/rmspritesheet.js +42 -0
  165. package/dist/presets/rmspritesheet.js.map +1 -0
  166. package/dist/services/AbstractSocket.d.ts +9 -5
  167. package/dist/services/AbstractSocket.js +11 -0
  168. package/dist/services/AbstractSocket.js.map +1 -0
  169. package/dist/services/keyboardControls.d.ts +15 -0
  170. package/dist/services/keyboardControls.js +23 -0
  171. package/dist/services/keyboardControls.js.map +1 -0
  172. package/dist/services/loadMap.d.ts +6 -0
  173. package/dist/services/loadMap.js +123 -0
  174. package/dist/services/loadMap.js.map +1 -0
  175. package/dist/services/mmorpg.d.ts +21 -9
  176. package/dist/services/mmorpg.js +136 -0
  177. package/dist/services/mmorpg.js.map +1 -0
  178. package/dist/services/save.d.ts +19 -0
  179. package/dist/services/save.js +77 -0
  180. package/dist/services/save.js.map +1 -0
  181. package/dist/services/save.spec.d.ts +1 -0
  182. package/dist/services/standalone.d.ts +67 -7
  183. package/dist/services/standalone.js +168 -0
  184. package/dist/services/standalone.js.map +1 -0
  185. package/dist/utils/getEntityProp.d.ts +39 -0
  186. package/dist/utils/getEntityProp.js +53 -0
  187. package/dist/utils/getEntityProp.js.map +1 -0
  188. package/dist/utils/getEntityProp.spec.d.ts +1 -0
  189. package/dist/utils/readPropValue.d.ts +2 -0
  190. package/dist/utils/readPropValue.js +13 -0
  191. package/dist/utils/readPropValue.js.map +1 -0
  192. package/package.json +14 -11
  193. package/src/Game/AnimationManager.spec.ts +30 -0
  194. package/src/Game/AnimationManager.ts +33 -0
  195. package/src/Game/Event.ts +1 -1
  196. package/src/Game/Map.ts +184 -3
  197. package/src/Game/Object.ts +409 -14
  198. package/src/Game/Player.ts +1 -1
  199. package/src/Gui/Gui.spec.ts +273 -0
  200. package/src/Gui/Gui.ts +566 -23
  201. package/src/Gui/NotificationManager.ts +69 -0
  202. package/src/Resource.ts +149 -0
  203. package/src/RpgClient.ts +309 -14
  204. package/src/RpgClientEngine.ts +1790 -63
  205. package/src/Sound.ts +253 -0
  206. package/src/components/{effects → animations}/animation.ce +3 -6
  207. package/src/components/{effects → animations}/index.ts +1 -1
  208. package/src/components/character.ce +801 -59
  209. package/src/components/dynamics/bar.ce +87 -0
  210. package/src/components/dynamics/image.ce +20 -0
  211. package/src/components/dynamics/parse-value.spec.ts +83 -0
  212. package/src/components/dynamics/parse-value.ts +154 -0
  213. package/src/components/dynamics/shape-utils.spec.ts +46 -0
  214. package/src/components/dynamics/shape-utils.ts +61 -0
  215. package/src/components/dynamics/shape.ce +89 -0
  216. package/src/components/dynamics/text.ce +68 -0
  217. package/src/components/gui/box.ce +17 -0
  218. package/src/components/gui/dialogbox/index.ce +213 -187
  219. package/src/components/gui/gameover.ce +158 -0
  220. package/src/components/gui/hud/hud.ce +61 -0
  221. package/src/components/gui/index.ts +30 -4
  222. package/src/components/gui/menu/equip-menu.ce +410 -0
  223. package/src/components/gui/menu/exit-menu.ce +41 -0
  224. package/src/components/gui/menu/items-menu.ce +317 -0
  225. package/src/components/gui/menu/main-menu.ce +294 -0
  226. package/src/components/gui/menu/options-menu.ce +35 -0
  227. package/src/components/gui/menu/skills-menu.ce +83 -0
  228. package/src/components/gui/mobile/index.ts +24 -0
  229. package/src/components/gui/mobile/mobile.ce +80 -0
  230. package/src/components/gui/notification/notification.ce +51 -0
  231. package/src/components/gui/save-load.ce +208 -0
  232. package/src/components/gui/shop/shop.ce +493 -0
  233. package/src/components/gui/title-screen.ce +163 -0
  234. package/src/components/index.ts +3 -0
  235. package/src/components/player-components-utils.spec.ts +109 -0
  236. package/src/components/player-components-utils.ts +205 -0
  237. package/src/components/player-components.ce +221 -0
  238. package/src/components/prebuilt/hp-bar.ce +255 -0
  239. package/src/components/prebuilt/index.ts +24 -0
  240. package/src/components/prebuilt/light-halo.ce +148 -0
  241. package/src/components/scenes/canvas.ce +185 -21
  242. package/src/components/scenes/draw-map.ce +55 -21
  243. package/src/components/scenes/event-layer.ce +8 -2
  244. package/src/components/scenes/transition.ce +60 -0
  245. package/src/core/setup.ts +2 -2
  246. package/src/decorators/spritesheet.ts +8 -0
  247. package/src/index.ts +17 -2
  248. package/src/module.ts +132 -10
  249. package/src/presets/animation.ts +46 -0
  250. package/src/presets/faceset.ts +60 -0
  251. package/src/presets/icon.ts +17 -0
  252. package/src/presets/index.ts +9 -1
  253. package/src/presets/lpc.ts +108 -0
  254. package/src/services/AbstractSocket.ts +10 -2
  255. package/src/services/keyboardControls.ts +20 -0
  256. package/src/services/loadMap.ts +3 -1
  257. package/src/services/mmorpg.ts +106 -12
  258. package/src/services/save.spec.ts +127 -0
  259. package/src/services/save.ts +103 -0
  260. package/src/services/standalone.ts +110 -18
  261. package/src/utils/getEntityProp.spec.ts +96 -0
  262. package/src/utils/getEntityProp.ts +88 -0
  263. package/src/utils/readPropValue.ts +16 -0
  264. package/vite.config.ts +4 -2
  265. package/dist/Game/EffectManager.d.ts +0 -5
  266. package/dist/components/effects/index.d.ts +0 -4
  267. package/dist/index.js.map +0 -1
  268. package/dist/index10.js +0 -8
  269. package/dist/index10.js.map +0 -1
  270. package/dist/index11.js +0 -10
  271. package/dist/index11.js.map +0 -1
  272. package/dist/index12.js +0 -8
  273. package/dist/index12.js.map +0 -1
  274. package/dist/index13.js +0 -17
  275. package/dist/index13.js.map +0 -1
  276. package/dist/index14.js +0 -107
  277. package/dist/index14.js.map +0 -1
  278. package/dist/index15.js +0 -50
  279. package/dist/index15.js.map +0 -1
  280. package/dist/index16.js +0 -191
  281. package/dist/index16.js.map +0 -1
  282. package/dist/index17.js +0 -9
  283. package/dist/index17.js.map +0 -1
  284. package/dist/index18.js +0 -387
  285. package/dist/index18.js.map +0 -1
  286. package/dist/index19.js +0 -31
  287. package/dist/index19.js.map +0 -1
  288. package/dist/index2.js +0 -181
  289. package/dist/index2.js.map +0 -1
  290. package/dist/index20.js +0 -24
  291. package/dist/index20.js.map +0 -1
  292. package/dist/index21.js +0 -2421
  293. package/dist/index21.js.map +0 -1
  294. package/dist/index22.js +0 -114
  295. package/dist/index22.js.map +0 -1
  296. package/dist/index23.js +0 -109
  297. package/dist/index23.js.map +0 -1
  298. package/dist/index24.js +0 -71
  299. package/dist/index24.js.map +0 -1
  300. package/dist/index25.js +0 -21
  301. package/dist/index25.js.map +0 -1
  302. package/dist/index26.js +0 -41
  303. package/dist/index26.js.map +0 -1
  304. package/dist/index27.js +0 -5
  305. package/dist/index27.js.map +0 -1
  306. package/dist/index28.js +0 -322
  307. package/dist/index28.js.map +0 -1
  308. package/dist/index29.js +0 -27
  309. package/dist/index29.js.map +0 -1
  310. package/dist/index3.js +0 -87
  311. package/dist/index3.js.map +0 -1
  312. package/dist/index30.js +0 -11
  313. package/dist/index30.js.map +0 -1
  314. package/dist/index31.js +0 -11
  315. package/dist/index31.js.map +0 -1
  316. package/dist/index32.js +0 -174
  317. package/dist/index32.js.map +0 -1
  318. package/dist/index33.js +0 -501
  319. package/dist/index33.js.map +0 -1
  320. package/dist/index34.js +0 -12
  321. package/dist/index34.js.map +0 -1
  322. package/dist/index35.js +0 -4403
  323. package/dist/index35.js.map +0 -1
  324. package/dist/index36.js +0 -316
  325. package/dist/index36.js.map +0 -1
  326. package/dist/index37.js +0 -61
  327. package/dist/index37.js.map +0 -1
  328. package/dist/index38.js +0 -20
  329. package/dist/index38.js.map +0 -1
  330. package/dist/index39.js +0 -20
  331. package/dist/index39.js.map +0 -1
  332. package/dist/index4.js +0 -67
  333. package/dist/index4.js.map +0 -1
  334. package/dist/index5.js +0 -16
  335. package/dist/index5.js.map +0 -1
  336. package/dist/index6.js +0 -17
  337. package/dist/index6.js.map +0 -1
  338. package/dist/index7.js +0 -39
  339. package/dist/index7.js.map +0 -1
  340. package/dist/index8.js +0 -108
  341. package/dist/index8.js.map +0 -1
  342. package/dist/index9.js +0 -76
  343. package/dist/index9.js.map +0 -1
  344. package/src/Game/EffectManager.ts +0 -20
  345. package/src/components/gui/dialogbox/itemMenu.ce +0 -23
  346. package/src/components/gui/dialogbox/selection.ce +0 -67
  347. /package/src/components/{effects → animations}/hit.ce +0 -0
@@ -0,0 +1,493 @@
1
+ <DOMContainer width="100%" height="100%">
2
+ <div class="rpg-shop-container rpg-anim-fade-in">
3
+ <div class="rpg-shop-header">
4
+ <div class="rpg-shop-merchant">
5
+ <div>
6
+ @if (hasFace) {
7
+ <div class="rpg-shop-merchant-avatar">
8
+ <DOMSprite
9
+ sheet={faceSheet(face().id, face().expression)}
10
+ width="50px"
11
+ height="50px"
12
+ objectFit="contain"
13
+ />
14
+ </div>
15
+ }
16
+ </div>
17
+ <div class="rpg-shop-merchant-info">
18
+ <p>{{ shopMessage() }}</p>
19
+ </div>
20
+ </div>
21
+ <div class="rpg-shop-gold">
22
+ {{ gold() }} {{ goldTerm }}
23
+ </div>
24
+ </div>
25
+
26
+ <div class="rpg-shop-body">
27
+ <div class="rpg-shop-left">
28
+ @if (tradeView() === 'mode') {
29
+ <div class="rpg-shop-content rpg-shop-content-mode">
30
+ <div class="rpg-shop-details rpg-shop-details-mode">
31
+ <div class="rpg-shop-details-header">
32
+ <div class="rpg-shop-details-icon">🛒</div>
33
+ <h2 style="margin: 0;">Choose an action</h2>
34
+ </div>
35
+ <div class="rpg-shop-trade">
36
+ <Navigation tabindex={selectedModeIndex} controls={modeControls}>
37
+ <div class="rpg-shop-tabs rpg-shop-trade-tabs">
38
+ <div
39
+ class="rpg-shop-tab"
40
+ class={{active: selectedModeIndex() === 0}}
41
+ click={selectMode('buy')}
42
+ >Buy</div>
43
+ <div
44
+ class="rpg-shop-tab"
45
+ class={{active: selectedModeIndex() === 1}}
46
+ click={selectMode('sell')}
47
+ >Sell</div>
48
+ </div>
49
+ </Navigation>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ }
54
+ @else {
55
+ <div>
56
+ <Navigation tabindex={selectedTab} controls={tabControls}>
57
+ <div class="rpg-shop-tabs">
58
+ @for ((tab,index) of tabs) {
59
+ <div
60
+ class="rpg-shop-tab"
61
+ class={{active: selectedTab() === index}}
62
+ tabindex={index}
63
+ click={selectTab(index)}
64
+ >{{ tab.label }}</div>
65
+ }
66
+ </div>
67
+ </Navigation>
68
+
69
+ <div class="rpg-shop-content">
70
+ <div class="rpg-shop-grid">
71
+ <Navigation tabindex={selectedItem} controls={itemControls}>
72
+ @for ((item,index) of filteredItems) {
73
+ <div class="rpg-shop-card" class={{disabled: isItemDisabled(item), selected: selectedItem() === index}} tabindex={index} click={selectItem(index)}>
74
+ <div class="rpg-shop-card-icon">
75
+ @if (item.icon) {
76
+ <DOMSprite
77
+ sheet={iconSheet(item.icon)}
78
+ playing="default"
79
+ width="48px"
80
+ height="48px"
81
+ objectFit="contain"
82
+ />
83
+ }
84
+ </div>
85
+ <div class="rpg-shop-card-name">{{ item.name }}</div>
86
+ <div class="rpg-shop-card-price">{{ item.price }} {{ goldTerm }}</div>
87
+ @if (item.quantity !== undefined) {
88
+ <div class="rpg-shop-card-qty">x{{ item.quantity }}</div>
89
+ }
90
+ @if (item.equipped) {
91
+ <div class="rpg-shop-card-tag">Equipped</div>
92
+ }
93
+ </div>
94
+ }
95
+ </Navigation>
96
+ </div>
97
+
98
+ <div class="rpg-shop-details">
99
+ <div class="rpg-shop-details-header">
100
+ <div class="rpg-shop-details-icon">
101
+ <DOMSprite
102
+ sheet={iconSheet(currentItem()?.icon)}
103
+ playing="default"
104
+ width="80px"
105
+ height="80px"
106
+ objectFit="contain"
107
+ />
108
+ </div>
109
+ <h2 style="margin: 0;">{{ currentItem()?.name || "" }}</h2>
110
+ <p style="color: #ffd700; font-weight: bold; margin: 8px 0;">{{ currentItem()?.price ?? 0 }} {{ goldTerm }}</p>
111
+ @if (currentItem()?.quantity !== undefined) {
112
+ <div class="rpg-shop-details-qty">Qty: x{{ currentItem()?.quantity }}</div>
113
+ }
114
+ </div>
115
+ <div>
116
+ @if (currentItem()?.equipped) {
117
+ <div class="rpg-shop-equipped">Already equipped</div>
118
+ }
119
+ </div>
120
+ <div class="rpg-shop-details-desc">
121
+ {{ currentItem()?.description || "" }}
122
+ </div>
123
+ <div>
124
+ @if (displayStats().length > 0) {
125
+ <div class="rpg-shop-stats">
126
+ @for ((stat,index) of displayStats) {
127
+ <div class="rpg-shop-stat" class={{positive: stat.delta > 0, negative: stat.delta < 0}}>
128
+ <div class="rpg-shop-stat-key">{{ stat.label }}</div>
129
+ <div class="rpg-shop-stat-value">
130
+ {{ stat.delta > 0 ? '+' : '' }}{{ stat.delta }}
131
+ </div>
132
+ @if (stat.current !== undefined) {
133
+ <div class="rpg-shop-stat-current">{{ stat.current }} → {{ stat.next }}</div>
134
+ }
135
+ </div>
136
+ }
137
+ </div>
138
+ }
139
+ </div>
140
+ <button class="rpg-shop-btn" click={backToMode()}>Back</button>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ }
145
+ @if (quantityDialogOpen) {
146
+ <div class="rpg-shop-modal">
147
+ <div class="rpg-shop-modal-card">
148
+ <div class="rpg-shop-modal-title">{{ actionLabel }}</div>
149
+ <div class="rpg-shop-modal-item">{{ currentItem()?.name || "" }}</div>
150
+ @if (currentItem()?.quantity !== undefined) {
151
+ <div class="rpg-shop-modal-qty">Available: x{{ currentItem()?.quantity }}</div>
152
+ }
153
+ <div class="rpg-shop-quantity">
154
+ <div class="rpg-shop-quantity-label">Quantity</div>
155
+ <div class="rpg-shop-quantity-controls">
156
+ <button class="rpg-shop-btn" click={changeQuantity(-1)}>-</button>
157
+ <div class="rpg-shop-quantity-value">{{ quantity }}</div>
158
+ <button class="rpg-shop-btn" click={changeQuantity(1)}>+</button>
159
+ </div>
160
+ </div>
161
+ <div class="rpg-shop-modal-total">
162
+ <span>Total</span>
163
+ <span>{{ totalPrice() }} {{ goldTerm }}</span>
164
+ </div>
165
+ <div class="rpg-shop-modal-actions">
166
+ <button class="rpg-shop-btn rpg-shop-btn-secondary" click={closeQuantityDialog()}>Cancel</button>
167
+ <button class="rpg-shop-btn" click={confirmTrade()}>
168
+ {{ actionLabel() }} x{{ quantity() }}
169
+ </button>
170
+ </div>
171
+ </div>
172
+ </div>
173
+ }
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </DOMContainer>
178
+
179
+ <script>
180
+ import { mount, signal, computed, createTabindexNavigator, effect } from "canvasengine";
181
+ import { inject } from "../../../core/inject";
182
+ import { RpgClientEngine } from "../../../RpgClientEngine";
183
+
184
+ const engine = inject(RpgClientEngine)
185
+ const currentPlayer = engine.scene.currentPlayer
186
+ const keyboardControls = engine.globalConfig.keyboardControls
187
+ const iconSheet = (iconId) => ({
188
+ definition: engine.getSpriteSheet(iconId),
189
+ playing: "default"
190
+ })
191
+ const goldTerm = engine.globalConfig.goldTerm || 'G'
192
+
193
+ const selectedItem = signal(0)
194
+ const selectedTab = signal(0)
195
+ const tradeMode = signal('buy')
196
+ const tradeView = signal('mode')
197
+ const selectedModeIndex = signal(0)
198
+ const quantity = signal(1)
199
+ const quantityDialogOpen = signal(false)
200
+ const defaultMessage = 'Welcome to my shop!'
201
+ const tabs = [
202
+ { id: 'item', label: 'Items' },
203
+ { id: 'weapon', label: 'Weapons' },
204
+ { id: 'armor', label: 'Armor' }
205
+ ]
206
+
207
+ const { data, onInteraction , onFinish } = defineProps()
208
+
209
+ const resolveProp = (value) => typeof value === "function" ? value() : value
210
+ const guiData = computed(() => resolveProp(data) || {})
211
+ const shopMessage = computed(() => {
212
+ const message = resolveProp(guiData().message)
213
+ return message ? String(message) : defaultMessage
214
+ })
215
+ const face = computed(() => resolveProp(guiData().face))
216
+ const hasFace = computed(() => {
217
+ const value = face()
218
+ return value && value.id
219
+ })
220
+ const buyItems = computed(() => guiData().items || [])
221
+ const sellItems = computed(() => guiData().sellItems || [])
222
+ const activeItems = computed(() => tradeMode() === 'buy' ? buyItems() : sellItems())
223
+ const filteredItems = computed(() => {
224
+ const tab = tabs[selectedTab()]
225
+ const items = activeItems()
226
+ if (!tab) return []
227
+ return items.filter((item) => item?.type === tab.id)
228
+ })
229
+ const currentItem = computed(() => filteredItems()[selectedItem()])
230
+ const gold = computed(() => currentPlayer()._gold())
231
+ const actionLabel = computed(() => tradeMode() === 'buy' ? 'Buy' : 'Sell')
232
+ const faceSheet = (graphicId, animationName) => ({
233
+ definition: engine.getSpriteSheet(graphicId),
234
+ playing: animationName || "default"
235
+ })
236
+ const maxQuantity = computed(() => {
237
+ const item = currentItem()
238
+ if (!item) return 0
239
+ const price = item?.price || 0
240
+ if (price <= 0) return 0
241
+ if (tradeMode() === 'sell') {
242
+ const qty = item?.quantity ?? 0
243
+ return Math.max(0, qty)
244
+ }
245
+ return Math.max(1, Math.floor(gold() / price))
246
+ })
247
+ const totalPrice = computed(() => {
248
+ const price = currentItem()?.price || 0
249
+ return price * quantity()
250
+ })
251
+ const displayStats = computed(() => {
252
+ const stats = currentItem()?.stats || {}
253
+ const params = guiData().playerParams || {}
254
+ const order = ['atk', 'def', 'pdef', 'sdef', 'str', 'dex', 'int', 'agi', 'maxHp', 'maxSp']
255
+ const labels = {
256
+ atk: 'ATK',
257
+ def: 'DEF',
258
+ pdef: 'PDEF',
259
+ sdef: 'SDEF',
260
+ str: 'STR',
261
+ dex: 'DEX',
262
+ int: 'INT',
263
+ agi: 'AGI',
264
+ maxHp: 'MAX HP',
265
+ maxSp: 'MAX SP'
266
+ }
267
+ const orderedKeys = order.filter((key) => stats[key] !== undefined)
268
+ const extraKeys = Object.keys(stats).filter((key) => !order.includes(key))
269
+ const keys = orderedKeys.concat(extraKeys)
270
+ const list = []
271
+ for (const key of keys) {
272
+ const delta = stats[key]
273
+ if (delta === undefined || delta === 0) continue
274
+ let current = params[key]
275
+ if (current === undefined && key === 'def') current = params.pdef
276
+ const next = current !== undefined ? current + delta : undefined
277
+ list.push({
278
+ key,
279
+ label: labels[key] || key.toUpperCase(),
280
+ delta,
281
+ current,
282
+ next
283
+ })
284
+ }
285
+ return list
286
+ })
287
+ const nav = createTabindexNavigator(selectedItem, { count: () => filteredItems().length }, 'wrap')
288
+ const navTab = createTabindexNavigator(selectedTab, { count: () => tabs.length }, 'wrap')
289
+ const navMode = createTabindexNavigator(selectedModeIndex, { count: () => 2 }, 'wrap')
290
+
291
+ function selectItem(index) {
292
+ return function() {
293
+ selectedItem.set(index)
294
+ quantity.set(1)
295
+ if (!isItemDisabled(filteredItems()[index])) {
296
+ quantityDialogOpen.set(true)
297
+ }
298
+ }
299
+ }
300
+
301
+ function selectTab(index) {
302
+ return function() {
303
+ selectedTab.set(index)
304
+ selectedItem.set(0)
305
+ }
306
+ }
307
+
308
+ function selectMode(mode) {
309
+ return function() {
310
+ tradeMode.set(mode)
311
+ selectedModeIndex.set(mode === 'buy' ? 0 : 1)
312
+ selectedItem.set(0)
313
+ quantity.set(1)
314
+ tradeView.set('items')
315
+ }
316
+ }
317
+
318
+ function isItemDisabled(item) {
319
+ if (!item) return true
320
+ const price = item?.price || 0
321
+ if (price <= 0) return true
322
+ if (tradeMode() === 'sell') {
323
+ const qty = item?.quantity ?? 0
324
+ return qty <= 0
325
+ }
326
+ return gold() < price
327
+ }
328
+
329
+ function backToMode() {
330
+ return function() {
331
+ tradeView.set('mode')
332
+ }
333
+ }
334
+
335
+ function changeQuantity(delta) {
336
+ return function() {
337
+ const limit = maxQuantity()
338
+ if (limit <= 0) return
339
+ const nextValue = Math.max(1, Math.min(limit, quantity() + delta))
340
+ if (nextValue !== quantity()) {
341
+ quantity.set(nextValue)
342
+ }
343
+ }
344
+ }
345
+
346
+ function closeQuantityDialog() {
347
+ return function() {
348
+ quantityDialogOpen.set(false)
349
+ }
350
+ }
351
+
352
+ function confirmTrade() {
353
+ return function() {
354
+ const item = currentItem()
355
+ if (!item || isItemDisabled(item)) {
356
+ quantityDialogOpen.set(false)
357
+ return
358
+ }
359
+ const action = tradeMode() === 'buy' ? 'buyItem' : 'sellItem'
360
+ onInteraction(action, { id: item.id, nb: quantity() })
361
+ quantityDialogOpen.set(false)
362
+ }
363
+ }
364
+
365
+ effect(() => {
366
+ const count = filteredItems().length
367
+ if (selectedItem() >= count) {
368
+ selectedItem.set(Math.max(0, count - 1))
369
+ }
370
+ })
371
+
372
+ const modeControls = signal({
373
+ left: {
374
+ repeat: true,
375
+ bind: keyboardControls.left,
376
+ throttle: 150,
377
+ keyDown() {
378
+ navMode.next(-1)
379
+ }
380
+ },
381
+ right: {
382
+ repeat: true,
383
+ bind: keyboardControls.right,
384
+ throttle: 150,
385
+ keyDown() {
386
+ navMode.next(1)
387
+ }
388
+ },
389
+ action: {
390
+ bind: keyboardControls.action,
391
+ keyDown() {
392
+ const mode = selectedModeIndex() === 0 ? 'buy' : 'sell'
393
+ tradeMode.set(mode)
394
+ selectedItem.set(0)
395
+ quantity.set(1)
396
+ tradeView.set('items')
397
+ }
398
+ },
399
+ escape: {
400
+ bind: keyboardControls.escape,
401
+ keyDown() {
402
+ onFinish()
403
+ }
404
+ },
405
+ gamepad: {
406
+ enabled: true
407
+ }
408
+ });
409
+
410
+ const itemControls = signal({
411
+ up: {
412
+ repeat: true,
413
+ bind: keyboardControls.up,
414
+ throttle: 150,
415
+ keyDown() {
416
+ if (quantityDialogOpen()) {
417
+ changeQuantity(1)()
418
+ return
419
+ }
420
+ nav.next(-1)
421
+ }
422
+ },
423
+ down: {
424
+ repeat: true,
425
+ bind: keyboardControls.down,
426
+ throttle: 150,
427
+ keyDown() {
428
+ if (quantityDialogOpen()) {
429
+ changeQuantity(-1)()
430
+ return
431
+ }
432
+ nav.next(1)
433
+ }
434
+ },
435
+ action: {
436
+ bind: keyboardControls.action,
437
+ keyDown() {
438
+ if (quantityDialogOpen()) {
439
+ const item = currentItem()
440
+ if (!item || isItemDisabled(item)) {
441
+ quantityDialogOpen.set(false)
442
+ return
443
+ }
444
+ const action = tradeMode() === 'buy' ? 'buyItem' : 'sellItem'
445
+ onInteraction(action, { id: item.id, nb: quantity() })
446
+ quantityDialogOpen.set(false)
447
+ return
448
+ }
449
+ const item = currentItem()
450
+ if (!isItemDisabled(item)) {
451
+ quantityDialogOpen.set(true)
452
+ }
453
+ }
454
+ },
455
+ escape: {
456
+ bind: keyboardControls.escape,
457
+ keyDown() {
458
+ if (quantityDialogOpen()) {
459
+ quantityDialogOpen.set(false)
460
+ return
461
+ }
462
+ tradeView.set('mode')
463
+ }
464
+ },
465
+ gamepad: {
466
+ enabled: true
467
+ }
468
+ });
469
+
470
+ const tabControls = signal({
471
+ left: {
472
+ repeat: true,
473
+ bind: keyboardControls.left,
474
+ throttle: 150,
475
+ keyDown() {
476
+ if (quantityDialogOpen()) return
477
+ navTab.next(-1)
478
+ }
479
+ },
480
+ right: {
481
+ repeat: true,
482
+ bind: keyboardControls.right,
483
+ throttle: 150,
484
+ keyDown() {
485
+ if (quantityDialogOpen()) return
486
+ navTab.next(1)
487
+ }
488
+ },
489
+ gamepad: {
490
+ enabled: true
491
+ }
492
+ })
493
+ </script>
@@ -0,0 +1,163 @@
1
+ <DOMContainer width="100%" height="100%">
2
+ <div class="rpg-ui-title-screen rpg-anim-fade-in">
3
+ <div class="rpg-ui-title-screen-header rpg-anim-float">
4
+ <div class="rpg-ui-title-screen-title">{titleText()}</div>
5
+ @if (subtitleText()) {
6
+ <div class="rpg-ui-title-screen-subtitle">{subtitleText()}</div>
7
+ }
8
+ </div>
9
+ <Navigation tabindex={selectedEntry} controls={controls}>
10
+ <div class="rpg-ui-menu rpg-ui-title-screen-menu rpg-anim-slide-up">
11
+ @for ((entry,index) of entryList()) {
12
+ <div
13
+ class="rpg-ui-menu-item"
14
+ class={{disabled: isEntryDisabled(entry)}}
15
+ data-selected={selectedEntry() === index ? "true" : "false"}
16
+ tabindex={index}
17
+ click={selectEntry(index)}
18
+ >{entry.label}</div>
19
+ }
20
+ </div>
21
+ </Navigation>
22
+ @if (versionText()) {
23
+ <div class="rpg-ui-title-screen-version">{versionText()}</div>
24
+ }
25
+ </div>
26
+ </DOMContainer>
27
+
28
+ <script>
29
+ import { signal, computed, effect } from "canvasengine";
30
+ import { PrebuiltGui } from "@rpgjs/common";
31
+ import { inject } from "../../core/inject";
32
+ import { RpgClientEngine } from "../../RpgClientEngine";
33
+ import { RpgGui } from "../../Gui/Gui";
34
+
35
+ const engine = inject(RpgClientEngine);
36
+ const guiService = inject(RpgGui);
37
+ const keyboardControls = engine.globalConfig.keyboardControls;
38
+
39
+ const { data, onInteraction } = defineProps({
40
+ entries: {
41
+ default: () => []
42
+ },
43
+ saveLoad: {
44
+ default: () => ({})
45
+ },
46
+ localActions: {
47
+ default: false
48
+ }
49
+ });
50
+
51
+ const { entries, title, subtitle, version, saveLoad, localActions } = data();
52
+
53
+ const defaultEntries = [
54
+ { id: "start", label: "Start" },
55
+ { id: "load", label: "Load" }
56
+ ];
57
+
58
+ const resolveProp = (value) => typeof value === "function" ? value() : value;
59
+ const titleText = computed(() => resolveProp(title) || "RPG");
60
+ const subtitleText = computed(() => resolveProp(subtitle) || "");
61
+ const versionText = computed(() => resolveProp(version) || "");
62
+ const localActionsEnabled = computed(() => resolveProp(localActions) === true);
63
+
64
+ const entryList = computed(() => {
65
+ const list = resolveProp(entries);
66
+ if (Array.isArray(list) && list.length) return list;
67
+ return defaultEntries;
68
+ });
69
+
70
+ const isEntryDisabled = (entry) => {
71
+ if (!entry) return true;
72
+ if (entry.disabled) return true;
73
+ if (entry.enabled === false) return true;
74
+ return false;
75
+ };
76
+
77
+ const selectedEntry = signal(0);
78
+ const selectableIndexes = computed(() => {
79
+ const list = entryList();
80
+ return list
81
+ .map((entry, index) => (isEntryDisabled(entry) ? null : index))
82
+ .filter((value) => value !== null);
83
+ });
84
+
85
+ effect(() => {
86
+ const available = selectableIndexes();
87
+ if (!available.length) return;
88
+ const current = selectedEntry();
89
+ if (!available.includes(current)) {
90
+ selectedEntry.set(available[0]);
91
+ }
92
+ });
93
+
94
+ const moveSelection = (delta) => {
95
+ const available = selectableIndexes();
96
+ if (!available.length) return;
97
+ const current = selectedEntry();
98
+ const currentIndex = Math.max(0, available.indexOf(current));
99
+ const nextIndex = (currentIndex + delta + available.length) % available.length;
100
+ selectedEntry.set(available[nextIndex]);
101
+ };
102
+
103
+ const triggerSelect = (index) => {
104
+ const list = entryList();
105
+ const entry = list[index];
106
+ if (!entry || isEntryDisabled(entry)) return;
107
+ if (localActionsEnabled()) {
108
+ if (entry.id === "start") {
109
+ guiService.hide(PrebuiltGui.TitleScreen);
110
+ }
111
+ if (entry.id === "load") {
112
+ const config = resolveProp(saveLoad) || {};
113
+ const slots = Array.isArray(config.slots) ? config.slots : [null, null, null];
114
+ guiService.display(PrebuiltGui.Save, {
115
+ ...config,
116
+ mode: config.mode || "load",
117
+ slots
118
+ });
119
+ }
120
+ }
121
+ if (onInteraction) {
122
+ onInteraction("select", { id: entry.id, index, entry });
123
+ }
124
+ };
125
+
126
+ function selectEntry(index) {
127
+ return function() {
128
+ selectedEntry.set(index);
129
+ triggerSelect(index);
130
+ };
131
+ }
132
+
133
+ const controls = signal({
134
+ up: {
135
+ repeat: true,
136
+ bind: keyboardControls.up,
137
+ throttle: 150,
138
+ keyDown() {
139
+ if (guiService.isDisplaying(PrebuiltGui.Save)) return;
140
+ moveSelection(-1);
141
+ }
142
+ },
143
+ down: {
144
+ repeat: true,
145
+ bind: keyboardControls.down,
146
+ throttle: 150,
147
+ keyDown() {
148
+ if (guiService.isDisplaying(PrebuiltGui.Save)) return;
149
+ moveSelection(1);
150
+ }
151
+ },
152
+ action: {
153
+ bind: keyboardControls.action,
154
+ keyDown() {
155
+ if (guiService.isDisplaying(PrebuiltGui.Save)) return;
156
+ triggerSelect(selectedEntry());
157
+ }
158
+ },
159
+ gamepad: {
160
+ enabled: true
161
+ }
162
+ });
163
+ </script>
@@ -1,4 +1,7 @@
1
1
  import EventLayerComponent from "./scenes/event-layer.ce";
2
2
  import CharacterComponent from "./character.ce";
3
3
 
4
+ // Prebuilt sprite components
5
+ export { HpBar } from "./prebuilt";
6
+
4
7
  export { EventLayerComponent, CharacterComponent }