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

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 (304) hide show
  1. package/dist/Game/AnimationManager.d.ts +8 -0
  2. package/dist/Game/AnimationManager.js +26 -0
  3. package/dist/Game/AnimationManager.js.map +1 -0
  4. package/dist/Game/Event.d.ts +1 -1
  5. package/dist/Game/Event.js +12 -0
  6. package/dist/Game/Event.js.map +1 -0
  7. package/dist/Game/Map.d.ts +23 -2
  8. package/dist/Game/Map.js +80 -0
  9. package/dist/Game/Map.js.map +1 -0
  10. package/dist/Game/Object.d.ts +157 -0
  11. package/dist/Game/Object.js +211 -0
  12. package/dist/Game/Object.js.map +1 -0
  13. package/dist/Game/Player.d.ts +1 -1
  14. package/dist/Game/Player.js +12 -0
  15. package/dist/Game/Player.js.map +1 -0
  16. package/dist/Gui/Gui.d.ts +177 -5
  17. package/dist/Gui/Gui.js +445 -0
  18. package/dist/Gui/Gui.js.map +1 -0
  19. package/dist/Gui/NotificationManager.d.ts +23 -0
  20. package/dist/Gui/NotificationManager.js +49 -0
  21. package/dist/Gui/NotificationManager.js.map +1 -0
  22. package/dist/Resource.d.ts +97 -0
  23. package/dist/Resource.js +133 -0
  24. package/dist/Resource.js.map +1 -0
  25. package/dist/RpgClient.d.ts +238 -11
  26. package/dist/RpgClientEngine.d.ts +615 -14
  27. package/dist/RpgClientEngine.js +1334 -0
  28. package/dist/RpgClientEngine.js.map +1 -0
  29. package/dist/Sound.d.ts +199 -0
  30. package/dist/Sound.js +167 -0
  31. package/dist/Sound.js.map +1 -0
  32. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/decorate.js +9 -0
  33. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/decorateMetadata.js +6 -0
  34. package/dist/components/animations/animation.ce.js +24 -0
  35. package/dist/components/animations/animation.ce.js.map +1 -0
  36. package/dist/components/animations/hit.ce.js +70 -0
  37. package/dist/components/animations/hit.ce.js.map +1 -0
  38. package/dist/components/animations/index.d.ts +4 -0
  39. package/dist/components/animations/index.js +11 -0
  40. package/dist/components/animations/index.js.map +1 -0
  41. package/dist/components/character.ce.js +392 -0
  42. package/dist/components/character.ce.js.map +1 -0
  43. package/dist/components/dynamics/parse-value.d.ts +1 -0
  44. package/dist/components/dynamics/parse-value.js +44 -0
  45. package/dist/components/dynamics/parse-value.js.map +1 -0
  46. package/dist/components/dynamics/text.ce.js +73 -0
  47. package/dist/components/dynamics/text.ce.js.map +1 -0
  48. package/dist/components/gui/box.ce.js +28 -0
  49. package/dist/components/gui/box.ce.js.map +1 -0
  50. package/dist/components/gui/dialogbox/index.ce.js +205 -0
  51. package/dist/components/gui/dialogbox/index.ce.js.map +1 -0
  52. package/dist/components/gui/gameover.ce.js +193 -0
  53. package/dist/components/gui/gameover.ce.js.map +1 -0
  54. package/dist/components/gui/hud/hud.ce.js +92 -0
  55. package/dist/components/gui/hud/hud.ce.js.map +1 -0
  56. package/dist/components/gui/index.d.ts +15 -3
  57. package/dist/components/gui/index.js +14 -0
  58. package/dist/components/gui/menu/equip-menu.ce.js +481 -0
  59. package/dist/components/gui/menu/equip-menu.ce.js.map +1 -0
  60. package/dist/components/gui/menu/exit-menu.ce.js +54 -0
  61. package/dist/components/gui/menu/exit-menu.ce.js.map +1 -0
  62. package/dist/components/gui/menu/items-menu.ce.js +344 -0
  63. package/dist/components/gui/menu/items-menu.ce.js.map +1 -0
  64. package/dist/components/gui/menu/main-menu.ce.js +417 -0
  65. package/dist/components/gui/menu/main-menu.ce.js.map +1 -0
  66. package/dist/components/gui/menu/options-menu.ce.js +48 -0
  67. package/dist/components/gui/menu/options-menu.ce.js.map +1 -0
  68. package/dist/components/gui/menu/skills-menu.ce.js +107 -0
  69. package/dist/components/gui/menu/skills-menu.ce.js.map +1 -0
  70. package/dist/components/gui/mobile/index.d.ts +8 -0
  71. package/dist/components/gui/mobile/index.js +21 -0
  72. package/dist/components/gui/mobile/index.js.map +1 -0
  73. package/dist/components/gui/mobile/mobile.ce.js +78 -0
  74. package/dist/components/gui/mobile/mobile.ce.js.map +1 -0
  75. package/dist/components/gui/notification/notification.ce.js +64 -0
  76. package/dist/components/gui/notification/notification.ce.js.map +1 -0
  77. package/dist/components/gui/save-load.ce.js +389 -0
  78. package/dist/components/gui/save-load.ce.js.map +1 -0
  79. package/dist/components/gui/shop/shop.ce.js +652 -0
  80. package/dist/components/gui/shop/shop.ce.js.map +1 -0
  81. package/dist/components/gui/title-screen.ce.js +190 -0
  82. package/dist/components/gui/title-screen.ce.js.map +1 -0
  83. package/dist/components/index.d.ts +1 -0
  84. package/dist/components/index.js +4 -0
  85. package/dist/components/prebuilt/hp-bar.ce.js +116 -0
  86. package/dist/components/prebuilt/hp-bar.ce.js.map +1 -0
  87. package/dist/components/prebuilt/index.d.ts +19 -0
  88. package/dist/components/prebuilt/index.js +2 -0
  89. package/dist/components/prebuilt/light-halo.ce.js +94 -0
  90. package/dist/components/prebuilt/light-halo.ce.js.map +1 -0
  91. package/dist/components/scenes/canvas.ce.js +60 -0
  92. package/dist/components/scenes/canvas.ce.js.map +1 -0
  93. package/dist/components/scenes/draw-map.ce.js +89 -0
  94. package/dist/components/scenes/draw-map.ce.js.map +1 -0
  95. package/dist/components/scenes/event-layer.ce.js +28 -0
  96. package/dist/components/scenes/event-layer.ce.js.map +1 -0
  97. package/dist/core/inject.js +18 -0
  98. package/dist/core/inject.js.map +1 -0
  99. package/dist/core/setup.js +16 -0
  100. package/dist/core/setup.js.map +1 -0
  101. package/dist/index.d.ts +15 -1
  102. package/dist/index.js +44 -14
  103. package/dist/module.d.ts +43 -4
  104. package/dist/module.js +176 -0
  105. package/dist/module.js.map +1 -0
  106. package/dist/node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js +277 -0
  107. package/dist/node_modules/.pnpm/@signe_di@2.9.0/node_modules/@signe/di/dist/index.js.map +1 -0
  108. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js +457 -0
  109. package/dist/node_modules/.pnpm/@signe_reactive@2.8.3/node_modules/@signe/reactive/dist/index.js.map +1 -0
  110. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js +463 -0
  111. package/dist/node_modules/.pnpm/@signe_reactive@2.9.0/node_modules/@signe/reactive/dist/index.js.map +1 -0
  112. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js +2191 -0
  113. package/dist/node_modules/.pnpm/@signe_room@2.9.0/node_modules/@signe/room/dist/index.js.map +1 -0
  114. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js +10 -0
  115. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/chunk-7QVYU63E.js.map +1 -0
  116. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js +91 -0
  117. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/client/index.js.map +1 -0
  118. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js +325 -0
  119. package/dist/node_modules/.pnpm/@signe_sync@2.9.0/node_modules/@signe/sync/dist/index.js.map +1 -0
  120. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js +14 -0
  121. package/dist/node_modules/.pnpm/dset@3.1.4/node_modules/dset/dist/index.js.map +1 -0
  122. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js +115 -0
  123. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-HAC622V3.js.map +1 -0
  124. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js +401 -0
  125. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/chunk-S74YV6PU.js.map +1 -0
  126. package/dist/node_modules/.pnpm/partysocket@1.1.3/node_modules/partysocket/dist/index.js +2 -0
  127. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js +3756 -0
  128. package/dist/node_modules/.pnpm/zod@3.24.2/node_modules/zod/lib/index.js.map +1 -0
  129. package/dist/presets/animation.d.ts +31 -0
  130. package/dist/presets/animation.js +39 -0
  131. package/dist/presets/animation.js.map +1 -0
  132. package/dist/presets/faceset.d.ts +30 -0
  133. package/dist/presets/faceset.js +51 -0
  134. package/dist/presets/faceset.js.map +1 -0
  135. package/dist/presets/icon.d.ts +20 -0
  136. package/dist/presets/icon.js +15 -0
  137. package/dist/presets/icon.js.map +1 -0
  138. package/dist/presets/index.d.ts +123 -0
  139. package/dist/presets/index.js +17 -0
  140. package/dist/presets/index.js.map +1 -0
  141. package/dist/presets/lpc.d.ts +89 -0
  142. package/dist/presets/lpc.js +98 -0
  143. package/dist/presets/lpc.js.map +1 -0
  144. package/dist/presets/rmspritesheet.js +42 -0
  145. package/dist/presets/rmspritesheet.js.map +1 -0
  146. package/dist/services/AbstractSocket.d.ts +9 -5
  147. package/dist/services/AbstractSocket.js +11 -0
  148. package/dist/services/AbstractSocket.js.map +1 -0
  149. package/dist/services/keyboardControls.d.ts +15 -0
  150. package/dist/services/keyboardControls.js +23 -0
  151. package/dist/services/keyboardControls.js.map +1 -0
  152. package/dist/services/loadMap.js +123 -0
  153. package/dist/services/loadMap.js.map +1 -0
  154. package/dist/services/mmorpg.d.ts +21 -9
  155. package/dist/services/mmorpg.js +131 -0
  156. package/dist/services/mmorpg.js.map +1 -0
  157. package/dist/services/save.d.ts +19 -0
  158. package/dist/services/save.js +77 -0
  159. package/dist/services/save.js.map +1 -0
  160. package/dist/services/standalone.d.ts +67 -7
  161. package/dist/services/standalone.js +168 -0
  162. package/dist/services/standalone.js.map +1 -0
  163. package/dist/utils/getEntityProp.d.ts +39 -0
  164. package/dist/utils/getEntityProp.js +52 -0
  165. package/dist/utils/getEntityProp.js.map +1 -0
  166. package/package.json +13 -9
  167. package/src/Game/{EffectManager.ts → AnimationManager.ts} +3 -2
  168. package/src/Game/Event.ts +1 -1
  169. package/src/Game/Map.ts +95 -3
  170. package/src/Game/Object.ts +330 -14
  171. package/src/Game/Player.ts +1 -1
  172. package/src/Gui/Gui.ts +506 -18
  173. package/src/Gui/NotificationManager.ts +69 -0
  174. package/src/Resource.ts +150 -0
  175. package/src/RpgClient.ts +246 -12
  176. package/src/RpgClientEngine.ts +1641 -62
  177. package/src/Sound.ts +253 -0
  178. package/src/components/{effects → animations}/animation.ce +3 -6
  179. package/src/components/{effects → animations}/index.ts +1 -1
  180. package/src/components/character.ce +387 -52
  181. package/src/components/dynamics/parse-value.ts +80 -0
  182. package/src/components/dynamics/text.ce +183 -0
  183. package/src/components/gui/box.ce +17 -0
  184. package/src/components/gui/dialogbox/index.ce +204 -187
  185. package/src/components/gui/gameover.ce +158 -0
  186. package/src/components/gui/hud/hud.ce +61 -0
  187. package/src/components/gui/index.ts +30 -4
  188. package/src/components/gui/menu/equip-menu.ce +410 -0
  189. package/src/components/gui/menu/exit-menu.ce +41 -0
  190. package/src/components/gui/menu/items-menu.ce +317 -0
  191. package/src/components/gui/menu/main-menu.ce +294 -0
  192. package/src/components/gui/menu/options-menu.ce +35 -0
  193. package/src/components/gui/menu/skills-menu.ce +83 -0
  194. package/src/components/gui/mobile/index.ts +24 -0
  195. package/src/components/gui/mobile/mobile.ce +80 -0
  196. package/src/components/gui/notification/notification.ce +51 -0
  197. package/src/components/gui/save-load.ce +208 -0
  198. package/src/components/gui/shop/shop.ce +493 -0
  199. package/src/components/gui/title-screen.ce +163 -0
  200. package/src/components/index.ts +3 -0
  201. package/src/components/prebuilt/hp-bar.ce +255 -0
  202. package/src/components/prebuilt/index.ts +24 -0
  203. package/src/components/prebuilt/light-halo.ce +148 -0
  204. package/src/components/scenes/canvas.ce +20 -15
  205. package/src/components/scenes/draw-map.ce +60 -13
  206. package/src/components/scenes/event-layer.ce +7 -0
  207. package/src/components/scenes/transition.ce +60 -0
  208. package/src/index.ts +16 -2
  209. package/src/module.ts +127 -9
  210. package/src/presets/animation.ts +46 -0
  211. package/src/presets/faceset.ts +60 -0
  212. package/src/presets/icon.ts +17 -0
  213. package/src/presets/index.ts +9 -1
  214. package/src/presets/lpc.ts +108 -0
  215. package/src/services/AbstractSocket.ts +10 -2
  216. package/src/services/keyboardControls.ts +20 -0
  217. package/src/services/loadMap.ts +1 -1
  218. package/src/services/mmorpg.ts +100 -12
  219. package/src/services/save.ts +103 -0
  220. package/src/services/standalone.ts +110 -18
  221. package/src/utils/getEntityProp.ts +87 -0
  222. package/vite.config.ts +4 -2
  223. package/dist/Game/EffectManager.d.ts +0 -5
  224. package/dist/components/effects/index.d.ts +0 -4
  225. package/dist/index.js.map +0 -1
  226. package/dist/index10.js +0 -8
  227. package/dist/index10.js.map +0 -1
  228. package/dist/index11.js +0 -10
  229. package/dist/index11.js.map +0 -1
  230. package/dist/index12.js +0 -8
  231. package/dist/index12.js.map +0 -1
  232. package/dist/index13.js +0 -17
  233. package/dist/index13.js.map +0 -1
  234. package/dist/index14.js +0 -107
  235. package/dist/index14.js.map +0 -1
  236. package/dist/index15.js +0 -50
  237. package/dist/index15.js.map +0 -1
  238. package/dist/index16.js +0 -191
  239. package/dist/index16.js.map +0 -1
  240. package/dist/index17.js +0 -9
  241. package/dist/index17.js.map +0 -1
  242. package/dist/index18.js +0 -387
  243. package/dist/index18.js.map +0 -1
  244. package/dist/index19.js +0 -31
  245. package/dist/index19.js.map +0 -1
  246. package/dist/index2.js +0 -181
  247. package/dist/index2.js.map +0 -1
  248. package/dist/index20.js +0 -24
  249. package/dist/index20.js.map +0 -1
  250. package/dist/index21.js +0 -2421
  251. package/dist/index21.js.map +0 -1
  252. package/dist/index22.js +0 -114
  253. package/dist/index22.js.map +0 -1
  254. package/dist/index23.js +0 -109
  255. package/dist/index23.js.map +0 -1
  256. package/dist/index24.js +0 -71
  257. package/dist/index24.js.map +0 -1
  258. package/dist/index25.js +0 -21
  259. package/dist/index25.js.map +0 -1
  260. package/dist/index26.js +0 -41
  261. package/dist/index26.js.map +0 -1
  262. package/dist/index27.js +0 -5
  263. package/dist/index27.js.map +0 -1
  264. package/dist/index28.js +0 -322
  265. package/dist/index28.js.map +0 -1
  266. package/dist/index29.js +0 -27
  267. package/dist/index29.js.map +0 -1
  268. package/dist/index3.js +0 -87
  269. package/dist/index3.js.map +0 -1
  270. package/dist/index30.js +0 -11
  271. package/dist/index30.js.map +0 -1
  272. package/dist/index31.js +0 -11
  273. package/dist/index31.js.map +0 -1
  274. package/dist/index32.js +0 -174
  275. package/dist/index32.js.map +0 -1
  276. package/dist/index33.js +0 -501
  277. package/dist/index33.js.map +0 -1
  278. package/dist/index34.js +0 -12
  279. package/dist/index34.js.map +0 -1
  280. package/dist/index35.js +0 -4403
  281. package/dist/index35.js.map +0 -1
  282. package/dist/index36.js +0 -316
  283. package/dist/index36.js.map +0 -1
  284. package/dist/index37.js +0 -61
  285. package/dist/index37.js.map +0 -1
  286. package/dist/index38.js +0 -20
  287. package/dist/index38.js.map +0 -1
  288. package/dist/index39.js +0 -20
  289. package/dist/index39.js.map +0 -1
  290. package/dist/index4.js +0 -67
  291. package/dist/index4.js.map +0 -1
  292. package/dist/index5.js +0 -16
  293. package/dist/index5.js.map +0 -1
  294. package/dist/index6.js +0 -17
  295. package/dist/index6.js.map +0 -1
  296. package/dist/index7.js +0 -39
  297. package/dist/index7.js.map +0 -1
  298. package/dist/index8.js +0 -108
  299. package/dist/index8.js.map +0 -1
  300. package/dist/index9.js +0 -76
  301. package/dist/index9.js.map +0 -1
  302. package/src/components/gui/dialogbox/itemMenu.ce +0 -23
  303. package/src/components/gui/dialogbox/selection.ce +0 -67
  304. /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 }