@yyyu-star/arcade-kit 0.10.2 → 0.11.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # 更新日志
2
2
 
3
+ ## 0.11.0
4
+
5
+ - **牌桌互动组件** `arcade-kit/table-fun`(仓库根 `docs/table-fun.md` 第 0 节"互动第二版"):几个牌桌游戏共用一套,游戏只给头像的屏幕矩形、禁区、发送通道、名场面映射和短语表。
6
+ - `TableFun`(DOM):头像上的透明热区(点别人出菜单、点自己出表情菜单;长按 0.4 秒连扔上次的道具 / 发上次的表情)、"互动"按钮和面板(短语 / 表情 / 道具、选对象、全部屏蔽)、
7
+ 菜单第一格是上次扔的道具、"屏蔽他"(sessionStorage `<id>.fun.blocked`,按 `scope` 分房间)、首次提示"点头像扔道具,长按连扔"(localStorage `<id>.hint.fun`,只一次)、
8
+ 冷却转圈、护盾、连击 ×N、回敬、名场面横幅 `banner`;菜单避开游戏给的禁区矩形,点按区 ≥ 44px。
9
+ - 单机(`localBots`)电脑由组件按 `botReact` 反应:一定是表情加一句话的气泡,回扔时道具飞回去;好友房电脑发来的东西晚 0.9 秒播、表情自动配一句话。
10
+ - `controls()` 给冒烟每个能点的东西的中心和大小,`log` 给一行行流水;演示页 `demo/table-fun.html`。
11
+ - **`arcade-kit/fun-logic`**(纯函数,房间、测试、页面都能用):`FUN_TIMING`(冷却 1.5 / 1 秒、护盾 10 秒 6 次、连击 3 秒、长按 0.4 秒、污渍 3 秒)、`FunCooldown`、`FunTally`、
12
+ `botReact(事件, 电脑, 状态, 现在, 随机数, 参数?)`(`BOT_REACT`:被扔 60% 回应、其中四分之一回扔、20 秒最多回扔 2 次,名场面输 40% / 赢 30%,每手 2 次,两次至少隔 1 秒;性格 ×1.5 / ×1 / ×0.3)、
13
+ `placeMenu`、编号换算 `funIdCount`/`funItem`/`stickerId`/`propId`,房间用的 `hitEvent`、`botEmoteIds`、`stickerMood`。
14
+ - `fun.ts`:污渍从约 1.7 秒改成 3 秒(`FUN_TIMING.stainMs`)。
15
+ - 测试 `test/fun-logic.test.ts`:botReact 的概率区间(按性格)、冷却、护盾、连击(换人断开)、回敬、回扔上限和窗口、每手上限、最小间隔、菜单避开禁区、编号和房间换算。
16
+
3
17
  ## 0.10.2
4
18
 
5
19
  - `standaloneRoot` 独立模式下也接 `/api/me`:回 200 `{ standalone: true }`(没有 `user`,页面的 `detectPlatform` 认作没有平台)。
package/README.md CHANGED
@@ -256,16 +256,89 @@ a daily write-quota meter (`arcade-kit/meter`), a seeded ChaCha20 RNG (`arcade-k
256
256
  - **互动道具** `throwAt(layer, from, to, prop, { sound?, onHit?, target? })`:8 种(`PROPS`:番茄、鸡蛋、臭鸡蛋、拖鞋、炸弹、玫瑰、点赞、干杯)。
257
257
  从 from 沿抛物线飞到 to,边飞边转,带两层残影,0.7 秒;命中:番茄爆开汁水四溅留果肉,鸡蛋蛋壳碎开、蛋清蛋黄糊上去往下流(臭鸡蛋再飘几缕绿色臭气),
258
258
  拖鞋拍扁弹开冒星星,炸弹引信闪三下再爆、冒烟、头像熏黑一下,玫瑰落下花瓣飘,点赞弹出带星星,干杯两杯碰一下冒泡沫。
259
- 污渍在头像上留约 1.7 秒再淡出,同一个人(`target`,游戏传座位号最稳)最多叠 3 层;
259
+ 污渍在头像上留 3 秒再淡出(0.11.0 起,原来约 1.7 秒),同一个人(`target`,游戏传座位号最稳)最多叠 3 层;
260
260
  - **头像的受击反应**由游戏做(头像在游戏的画布或 DOM 里):命中时 kit 调 `onHit(prop)`,游戏让头像抖一下、缩一下;
261
261
  - **音效**:`throwAt` 在起飞、炸弹引信、命中时调 `sound(prop, phase)`,游戏判断静音后用 `playFunSound(自己的 AudioContext, 输出节点, prop, phase)` 放(WebAudio 现场合成);
262
262
  - **性能**:只动 `transform`、`opacity`(合成层完成,不触发重排,不读布局),图层 `contain: strict`;同一个图层同时最多 `MAX_PLAYING`(4)个效果,多的直接丢掉(返回 false);
263
263
  - **素材**:全部是 kit 自己手写的 SVG(`src/fun-art.ts`,viewBox 0 0 100 100),不用 emoji 字体(有的设备显示成方框)、不引外部图片和字体,许可同 kit 本身;
264
264
  - **演示页**:`demo/index.html`,在 kit 目录里用任意能跑 TS 的开发服务器打开(如 `npx vite`,再访问 `/demo/`),每种道具、每个表情都有按钮。
265
- - **房间以外的 DO 用计量**
265
+ - **牌桌互动组件** `arcade-kit/table-fun`(0.11.0):头像菜单、互动面板、冷却护盾连击回敬、电脑反应整套,见下一节。
266
266
  - **房间以外的 DO 用计量** `meterReport(env, writes)`、`meterLevel(env)`(`arcade-kit/meter`):比如游戏自己的钱包 DO,每次写完报一次、写之前问一下门槛(`stop` 就别写了)。
267
267
  计量每收一次报数自己写 1 行,所以只适合写得少的地方;没绑 `METER` 时回 `ok`、什么都不做,连不上时抛错。
268
268
 
269
+ ## 牌桌互动(table-fun,0.11.0)
270
+
271
+ 几个牌桌游戏共用的一整套互动:外观、位置规则、节奏、电脑怎么反应都在 kit 里,游戏只做接线。规范正本是仓库根的 `docs/table-fun.md`(第 0 节分工,第 2–4 节的数字)。
272
+
273
+ | kit 管 | 游戏管 |
274
+ |---|---|
275
+ | 点头像菜单、互动面板(短语 / 表情 / 道具)、自己的表情菜单、首次提示 | 每个座位头像的**屏幕矩形**、名字、是不是自己、是不是电脑、互动性格 |
276
+ | 冷却(道具 1.5 秒、表情和短语 1 秒)、护盾(同一人 10 秒最多被扔 6 次)、连击 ×N、回敬 | 菜单不能盖的地方(手牌、操作按钮)的屏幕矩形 |
277
+ | 长按 0.4 秒连扔、菜单第一格是上次扔的道具、污渍 3 秒淡出 | 发送通道(好友房走 kit 的 emote,单机直接回给组件) |
278
+ | 电脑的反应 `botReact`(一定是表情 + 一句话,回扔时再带道具)、名场面横幅 | 把自己的公开事件映射成名场面(`bomb`、`first-out`、`big-win`、`kong`、`self-draw`……)、短语表 |
279
+
280
+ ### 页面里接上
281
+
282
+ ```ts
283
+ import { TableFun, funIdCount, type FunSeat } from 'arcade-kit/table-fun';
284
+
285
+ const fun = new TableFun({
286
+ storageKey: 'mygame', // 存储前缀:mygame.hint.fun(localStorage)、mygame.fun.blocked(sessionStorage)
287
+ phrases: PHRASES, // 本游戏的短语表;编号 0..P-1 是短语,P..P+11 表情,P+12..P+19 道具
288
+ named: [3, 4, 2], // 头像菜单里的 3 句点名短语(短语表下标)
289
+ seats: (): (FunSeat | null)[] => view.seats.map((s, i) => s && ({
290
+ rect: avatarRect(i), // 屏幕矩形(CSS 像素);DOM 头像直接 getBoundingClientRect()
291
+ name: s.name, me: i === 0, bot: s.bot, temper: s.temper, // temper:'rowdy' | 'normal' | 'cool'
292
+ })),
293
+ avoid: () => [handRect(), actionBarRect()], // 菜单、面板尽量不盖;放不下时选盖得最少的位置
294
+ button: () => funButtonRect(), // "互动"按钮放哪;null 不画(没坐下)
295
+ send: (id, to) => (online ? client.emote(id, to) : fun.receive(0, id, to)),
296
+ canSend: () => seated,
297
+ enabled: () => settings.fun, // 设置里关掉:别人的一律不播,单机电脑也不反应
298
+ scope: () => roomCode ?? 'solo', // "屏蔽他""全部屏蔽"按房间分开
299
+ localBots: !online, // 单机:电脑的反应由组件算、在本地播
300
+ sound: (prop, phase) => muted || playFunSound(ac, sfxBus, prop, phase),
301
+ onHit: (seat) => shakeAvatar(seat),
302
+ });
303
+ client.onEmote = (m) => fun.receive(m.from, m.id, m.to); // 好友房收到的(自己发的也是从这里回来)
304
+ ```
305
+
306
+ - **画布游戏**(Phaser 等):`rect` 传头像换算到屏幕后的矩形,算法是 `canvas.getBoundingClientRect()` 的左上角加上"世界坐标 × 画布在屏幕上的缩放"。
307
+ 组件每次用到时现问,座位挪了、窗口变了都跟得上;窗口尺寸变了它自己 `refresh()`,游戏重排头像后也调一次。
308
+ - **房间的编号数**:`RoomGame.emotes` 填 `funIdCount(PHRASES.length)`(短语 + 12 表情 + 8 道具)。
309
+ - **名场面**:游戏从**公开事件**里认出来,调 `fun.moment({ kind: 'moment', moment: 'bomb', winners: [0], losers: [1, 3], hand: 第几手 })`,
310
+ 单机时电脑按性格冲赢家撇嘴、或得意一下;要横幅就 `fun.banner('炸弹!', '小王 炸了 老李')`。
311
+ - **游戏自己的弹窗**:打开前 `fun.hide()`,关掉后 `fun.show()`(正在播的不中断);离开牌桌 `fun.destroy()`。
312
+ - **冒烟**:`fun.controls()` 给每个能点的东西的屏幕中心和大小(`fun:button`、`fun:seat<i>`、菜单里的 `fun:prop<k>`、`fun:named<k>`、`fun:block`、
313
+ 表情菜单 `fun:sticker<k>`、面板 `fun:tab:phrase|sticker|prop`、`fun:phrase<i>`、`fun:psticker<k>`、`fun:pprop<k>`、`fun:target<i>`、`fun:blockAll`);
314
+ `log` 选项给一行行流水(`道具 0>1:tomato ×2 回敬`、`电脑 1:angry`、`护盾 1`、`提示 头像`),断言用它。
315
+ - 演示页 `demo/table-fun.html`(`npx vite` 后打开 `/demo/table-fun.html`):我加三个不同性格的电脑,单机接法。
316
+
317
+ ### 房间里的电脑(好友房)
318
+
319
+ 纯逻辑在 `arcade-kit/fun-logic`(不碰 DOM,房间、测试都能 import;`table-fun` 也把它全部转出):
320
+
321
+ ```ts
322
+ import { botReact, botEmoteIds, hitEvent, newBotState, type BotState } from 'arcade-kit/fun-logic';
323
+
324
+ private bots = newBotState(); // 只在内存里,不写存储;房间重启丢了没关系
325
+ protected override onEmote(from: number, id: number, to?: number): void {
326
+ const ev = hitEvent(id, PHRASES.length, from, to); // 冲人来的道具、点名短语才算
327
+ if (!ev || !this.isBot(ev.to)) return;
328
+ const a = botReact(ev, { seat: ev.to, temper: temperOf(ev.to) }, this.bots, Date.now(), Math.random);
329
+ if (a) for (const e of botEmoteIds(a, PHRASES.length)) this.botEmote(a.from, e.id, e.to);
330
+ }
331
+ ```
332
+
333
+ - 房间只有一个闹钟,`a.delay` 不用等,立刻发;页面上的 `TableFun` 收到电脑座位(`bot: true`)发来的东西会晚 0.9 秒再播,
334
+ 表情自动配一句话(`moodLines` 或 kit 默认),看起来和单机的电脑一样。名场面同理:在 `onStep` 里从公开事件认出来,每个电脑座位问一次 `botReact`。
335
+
336
+ - `botReact(事件, 电脑, 状态, 现在, 随机数, 参数?)` 返回 `null`(不理)或 `{ from, to?, delay, sticker, mood, prop? }`:被扔后 60% 回应(乘性格:爱闹 ×1.5、普通 ×1、高冷 ×0.3),
337
+ 其中四分之一同类回扔(鸡蛋回拖鞋;同一个电脑 20 秒最多回扔 2 次);名场面输的一方 40% 冲赢家、赢的一方 30% 得意;每手最多主动 2 次;两次反应至少隔 1 秒。
338
+ 数字都在 `BOT_REACT`,第六个参数能整个换掉。
339
+ - 电脑的反应只是画面,**出牌决策绝不读它**;真人的短语、道具不记进牌局状态(见上面 `onEmote` 的规矩)。
340
+ - 其他纯函数:`stickerMood`(表情对应的情绪)、`FunCooldown`(冷却)、`FunTally`(护盾、连击、回敬)、`placeMenu`(菜单放哪,避开禁区)、`funItem`/`stickerId`/`propId`(编号换算),测试在 `test/fun-logic.test.ts`。
341
+
269
342
  ## 房间怎么守规矩
270
343
 
271
344
  - **只用 `ctx.acceptWebSocket`、一个闹钟**:所有到期时间(房间寿命 3 小时、没人 10 分钟、这一手 30 秒、掉线宽限 60 秒、电脑没算完、停够了(0.5.0))取最早的;
@@ -429,6 +502,8 @@ packages/arcade-kit/
429
502
  │ ├─ protocol.ts 消息类型、关闭码、协议版本
430
503
  │ ├─ rng.ts ChaCha20 随机数
431
504
  │ ├─ fun.ts、fun-art.ts 快捷短语、表情、道具的画面层
505
+ │ ├─ fun-logic.ts 牌桌互动的规则:冷却、护盾、连击、回敬、电脑反应、菜单位置(纯函数)
506
+ │ ├─ table-fun.ts 牌桌互动组件 TableFun(DOM:头像菜单、面板、提示)
432
507
  │ ├─ testing.ts 假平台钱包(只给测试和本地开发)
433
508
  │ └─ internal.ts 内部地址、身份头(不在 exports 里)
434
509
  ├─ scripts/manifest.mjs 打包时把 exports 换成 dist 版、换回来、检查 dist
@@ -0,0 +1,184 @@
1
+ /**
2
+ * 牌桌互动的规则(0.11.0):冷却、护盾、连击、回敬、电脑怎么反应、菜单放哪。纯函数和小类,不碰 DOM,时间和随机数由调用方给,
3
+ * 页面(table-fun.ts)和房间(电脑在服务器上回应时)都能用,测试在 workerd 里直接跑。
4
+ *
5
+ * 座位用游戏自己的编号(页面上一般是"我 = 0"的画面座位,房间里是真实座位),这里不关心是哪种,只要同一个对象里一致。
6
+ * 所有数字的出处是仓库根 docs/table-fun.md 第 2–4 节;都能经参数改,默认值就是规范。
7
+ */
8
+ import { PROPS, STICKERS, type PropId, type StickerId } from './fun-art.js';
9
+ export { PROPS, STICKERS, type PropId, type StickerId };
10
+ export declare const FUN_TIMING: {
11
+ /** 自己扔道具的冷却 */
12
+ readonly propCooldownMs: 1500;
13
+ /** 表情、短语的冷却 */
14
+ readonly talkCooldownMs: 1000;
15
+ /** 同一个人 shieldWindowMs 里最多被扔 shieldMax 次,多的亮护盾、不播 */
16
+ readonly shieldMax: 6;
17
+ readonly shieldWindowMs: 10000;
18
+ /** 连击、回敬都按这个算 */
19
+ readonly comboMs: 3000;
20
+ /** 长按多久算"连扔上次那个" */
21
+ readonly longPressMs: 400;
22
+ /** 污渍留多久再淡出 */
23
+ readonly stainMs: 3000;
24
+ /** 首次提示留多久 */
25
+ readonly hintMs: 3000;
26
+ /** 好友房的电脑从房间立刻发出来(房间只有一个闹钟),页面晚这么久再播,像人反应了一下、也等道具落地 */
27
+ readonly botLagMs: 900;
28
+ };
29
+ export type FunKind = 'prop' | 'talk';
30
+ /** 自己发东西的冷却:道具一个计时,表情和短语共用一个 */
31
+ export declare class FunCooldown {
32
+ private readonly ms;
33
+ private last;
34
+ constructor(ms?: Record<FunKind, number>);
35
+ /** 还要等多久(毫秒,0 = 能发) */
36
+ left(kind: FunKind, now: number): number;
37
+ /** 能发就记下并返回 true;冷却中返回 false,不记 */
38
+ take(kind: FunKind, now: number): boolean;
39
+ total(kind: FunKind): number;
40
+ }
41
+ export interface HitResult {
42
+ /** 被扔太多了:这一下不播,头像上亮护盾 */
43
+ shield: boolean;
44
+ /** 同一个人连着扔同一个人的第几下(1 = 不算连击) */
45
+ combo: number;
46
+ /** 被 to 扔过以后 comboMs 内扔回去 */
47
+ revenge: boolean;
48
+ }
49
+ /** 每一下扔中都过这里;真人、电脑、好友房转发来的一视同仁 */
50
+ export declare class FunTally {
51
+ private readonly t;
52
+ private readonly hits;
53
+ /** 每个人最近一次扔的是谁、第几下:换了目标就断("连续扔同一个人") */
54
+ private readonly chain;
55
+ /** 谁最近扔过这个人 */
56
+ private readonly lastBy;
57
+ constructor(t?: {
58
+ shieldMax: number;
59
+ shieldWindowMs: number;
60
+ comboMs: number;
61
+ });
62
+ hit(from: number, to: number, now: number): HitResult;
63
+ }
64
+ /** 互动性格:爱闹 / 普通 / 高冷(每个电脑人物一个,写在游戏的人物表里) */
65
+ export type FunTemper = 'rowdy' | 'normal' | 'cool';
66
+ export declare const TEMPER_MULT: Record<FunTemper, number>;
67
+ /** 反应的情绪:决定冒哪个表情、气泡说哪类话(话由游戏给,kit 有一套不提任何游戏的默认) */
68
+ export type FunMood = 'angry' | 'sweat' | 'love' | 'smug' | 'shock' | 'cry';
69
+ /** 名场面:游戏把自己的公开事件映射成这几类,没有的不报 */
70
+ export type MomentKind = 'big-win' | 'comeback' | 'bluff-caught' | 'bomb' | 'first-out' | 'double-down' | 'kong' | 'self-draw' | (string & {});
71
+ /** 发给 botReact 的事 */
72
+ export type FunEvent =
73
+ /** 有人冲这个电脑扔了道具(prop)或点名短语(没有 prop) */
74
+ {
75
+ kind: 'hit';
76
+ from: number;
77
+ to: number;
78
+ prop?: PropId;
79
+ }
80
+ /** 名场面:赢的、输的各是谁;hand 区分"这一手"(每手电脑主动互动有上限) */
81
+ | {
82
+ kind: 'moment';
83
+ moment: MomentKind;
84
+ winners: readonly number[];
85
+ losers: readonly number[];
86
+ hand: string | number;
87
+ };
88
+ export interface FunBot {
89
+ seat: number;
90
+ temper: FunTemper;
91
+ }
92
+ /** 电脑这一下要做什么:一定有表情和一句话的情绪(看得见),回敬时再带一个道具飞过去 */
93
+ export interface BotAction {
94
+ from: number;
95
+ /** 道具、点名的对象 */
96
+ to?: number;
97
+ /** 过多久做(像人一样反应一下) */
98
+ delay: number;
99
+ sticker: StickerId;
100
+ mood: FunMood;
101
+ prop?: PropId;
102
+ }
103
+ export interface BotReactConfig {
104
+ /** 被扔后回应的概率(再乘性格) */
105
+ respond: number;
106
+ /** 回应里直接回敬道具的比例 */
107
+ counterShare: number;
108
+ /** 同一个电脑 counterWindowMs 里最多回敬几次 */
109
+ counterMax: number;
110
+ counterWindowMs: number;
111
+ /** 同一个电脑两次反应至少隔多久(不能比扔道具的冷却长,否则连扔时回应被吞) */
112
+ minGapMs: number;
113
+ /** 反应延迟区间 */
114
+ delay: readonly [number, number];
115
+ /** 名场面:输的一方冲赢家、赢的一方得意 */
116
+ momentLose: number;
117
+ momentWin: number;
118
+ /** 每一手电脑主动互动最多几次 */
119
+ perHand: number;
120
+ }
121
+ export declare const BOT_REACT: BotReactConfig;
122
+ /** 电脑反应的账:调用方存着(页面一局一份;房间放内存) */
123
+ export interface BotState {
124
+ lastOut: Record<number, number>;
125
+ counters: Record<number, number[]>;
126
+ hand: string | number | null;
127
+ /** 这一手已经主动互动了几次 */
128
+ n: number;
129
+ }
130
+ export declare function newBotState(): BotState;
131
+ /** 同类回敬:番茄还番茄,鸡蛋还拖鞋(一个比一个狠一点),善意的还善意的 */
132
+ export declare const COUNTER: Record<PropId, PropId>;
133
+ /**
134
+ * 一个电脑对一件事的反应,没有就是 null。被扔:bot 是被扔的那个;名场面:调用方把每个电脑都问一遍(每手有上限,按问的顺序先到先得)。
135
+ * 被扔时的回应不占"每手主动互动"的次数,只守 minGapMs 和回敬上限。
136
+ */
137
+ export declare function botReact(ev: FunEvent, bot: FunBot, st: BotState, now: number, rand: () => number, cfg?: BotReactConfig): BotAction | null;
138
+ export interface Box {
139
+ left: number;
140
+ top: number;
141
+ width: number;
142
+ height: number;
143
+ }
144
+ /**
145
+ * 菜单(w×h)贴着头像(anchor)放:先试朝屏幕中心那一侧,再试另外三侧;夹在可见区里(留 margin),
146
+ * 和"禁区"(手牌、操作按钮)以及头像本身压得最少的那个位置胜出,一样少时按试的顺序。
147
+ */
148
+ export declare function placeMenu(anchor: Box, w: number, h: number, view: {
149
+ width: number;
150
+ height: number;
151
+ }, avoid?: readonly Box[], margin?: number, gap?: number): {
152
+ left: number;
153
+ top: number;
154
+ };
155
+ /**
156
+ * 编号怎么排(和房间转发的 emote id 一致):短语 0..P-1,表情 P..P+11,道具 P+12..P+19。P 是游戏短语表的长度。
157
+ * 游戏的 RoomGame.emotes 写 funIdCount(P)。
158
+ */
159
+ export declare function funIdCount(phrases: number): number;
160
+ export type FunItem = {
161
+ kind: 'phrase';
162
+ index: number;
163
+ } | {
164
+ kind: 'sticker';
165
+ index: number;
166
+ } | {
167
+ kind: 'prop';
168
+ index: number;
169
+ };
170
+ export declare function funItem(id: number, phrases: number): FunItem | null;
171
+ export declare const stickerId: (phrases: number, index: number) => number;
172
+ export declare const propId: (phrases: number, index: number) => number;
173
+ /** 电脑的表情对应的情绪(页面收到电脑的表情时配一句话用);不是情绪表情的回 null */
174
+ export declare function stickerMood(s: StickerId): FunMood | null;
175
+ /** 房间用:真人发来的编号换成给 botReact 的"被扔"(冲人来的道具、点名短语才算,表情、不点名的短语不算) */
176
+ export declare function hitEvent(id: number, phrases: number, from: number, to?: number): Extract<FunEvent, {
177
+ kind: 'hit';
178
+ }> | null;
179
+ /** 房间用:电脑的反应换成要经 botEmote 发的编号。先表情(页面会配上一句话),回扔时再加道具 */
180
+ export declare function botEmoteIds(a: BotAction, phrases: number): {
181
+ id: number;
182
+ to?: number;
183
+ }[];
184
+ //# sourceMappingURL=fun-logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fun-logic.d.ts","sourceRoot":"","sources":["../src/fun-logic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,249 @@
1
+ /**
2
+ * 牌桌互动的规则(0.11.0):冷却、护盾、连击、回敬、电脑怎么反应、菜单放哪。纯函数和小类,不碰 DOM,时间和随机数由调用方给,
3
+ * 页面(table-fun.ts)和房间(电脑在服务器上回应时)都能用,测试在 workerd 里直接跑。
4
+ *
5
+ * 座位用游戏自己的编号(页面上一般是"我 = 0"的画面座位,房间里是真实座位),这里不关心是哪种,只要同一个对象里一致。
6
+ * 所有数字的出处是仓库根 docs/table-fun.md 第 2–4 节;都能经参数改,默认值就是规范。
7
+ */
8
+ import { PROPS, STICKERS } from './fun-art.js';
9
+ export { PROPS, STICKERS };
10
+ // ---------- 节奏 ----------
11
+ export const FUN_TIMING = {
12
+ /** 自己扔道具的冷却 */
13
+ propCooldownMs: 1500,
14
+ /** 表情、短语的冷却 */
15
+ talkCooldownMs: 1000,
16
+ /** 同一个人 shieldWindowMs 里最多被扔 shieldMax 次,多的亮护盾、不播 */
17
+ shieldMax: 6,
18
+ shieldWindowMs: 10_000,
19
+ /** 连击、回敬都按这个算 */
20
+ comboMs: 3000,
21
+ /** 长按多久算"连扔上次那个" */
22
+ longPressMs: 400,
23
+ /** 污渍留多久再淡出 */
24
+ stainMs: 3000,
25
+ /** 首次提示留多久 */
26
+ hintMs: 3000,
27
+ /** 好友房的电脑从房间立刻发出来(房间只有一个闹钟),页面晚这么久再播,像人反应了一下、也等道具落地 */
28
+ botLagMs: 900,
29
+ };
30
+ /** 自己发东西的冷却:道具一个计时,表情和短语共用一个 */
31
+ export class FunCooldown {
32
+ ms;
33
+ last = { prop: -Infinity, talk: -Infinity };
34
+ constructor(ms = { prop: FUN_TIMING.propCooldownMs, talk: FUN_TIMING.talkCooldownMs }) {
35
+ this.ms = ms;
36
+ }
37
+ /** 还要等多久(毫秒,0 = 能发) */
38
+ left(kind, now) {
39
+ return Math.max(0, this.last[kind] + this.ms[kind] - now);
40
+ }
41
+ /** 能发就记下并返回 true;冷却中返回 false,不记 */
42
+ take(kind, now) {
43
+ if (this.left(kind, now) > 0)
44
+ return false;
45
+ this.last[kind] = now;
46
+ return true;
47
+ }
48
+ total(kind) {
49
+ return this.ms[kind];
50
+ }
51
+ }
52
+ /** 每一下扔中都过这里;真人、电脑、好友房转发来的一视同仁 */
53
+ export class FunTally {
54
+ t;
55
+ hits = new Map();
56
+ /** 每个人最近一次扔的是谁、第几下:换了目标就断("连续扔同一个人") */
57
+ chain = new Map();
58
+ /** 谁最近扔过这个人 */
59
+ lastBy = new Map();
60
+ constructor(t = FUN_TIMING) {
61
+ this.t = t;
62
+ }
63
+ hit(from, to, now) {
64
+ const recent = (this.hits.get(to) ?? []).filter((x) => now - x < this.t.shieldWindowMs);
65
+ if (recent.length >= this.t.shieldMax) {
66
+ this.hits.set(to, recent);
67
+ return { shield: true, combo: 1, revenge: false };
68
+ }
69
+ recent.push(now);
70
+ this.hits.set(to, recent);
71
+ const prev = this.chain.get(from);
72
+ const combo = prev && prev.to === to && now - prev.t <= this.t.comboMs ? prev.n + 1 : 1;
73
+ this.chain.set(from, { to, t: now, n: combo });
74
+ const by = this.lastBy.get(from);
75
+ const revenge = !!by && by.from === to && now - by.t <= this.t.comboMs;
76
+ this.lastBy.set(to, { from, t: now });
77
+ return { shield: false, combo, revenge };
78
+ }
79
+ }
80
+ export const TEMPER_MULT = { rowdy: 1.5, normal: 1, cool: 0.3 };
81
+ export const BOT_REACT = {
82
+ respond: 0.6,
83
+ counterShare: 0.25,
84
+ counterMax: 2,
85
+ counterWindowMs: 20_000,
86
+ minGapMs: 1000,
87
+ delay: [800, 2000],
88
+ momentLose: 0.4,
89
+ momentWin: 0.3,
90
+ perHand: 2,
91
+ };
92
+ export function newBotState() {
93
+ return { lastOut: {}, counters: {}, hand: null, n: 0 };
94
+ }
95
+ const DIRTY = ['tomato', 'egg', 'stinkyEgg', 'slipper', 'bomb'];
96
+ /** 同类回敬:番茄还番茄,鸡蛋还拖鞋(一个比一个狠一点),善意的还善意的 */
97
+ export const COUNTER = {
98
+ tomato: 'tomato',
99
+ egg: 'slipper',
100
+ stinkyEgg: 'stinkyEgg',
101
+ slipper: 'slipper',
102
+ bomb: 'bomb',
103
+ rose: 'rose',
104
+ like: 'like',
105
+ cheers: 'cheers',
106
+ };
107
+ const MOOD_STICKER = {
108
+ angry: ['angry'],
109
+ sweat: ['sweat'],
110
+ love: ['love'],
111
+ smug: ['smug', 'cool', 'lol'],
112
+ shock: ['shock'],
113
+ cry: ['cry'],
114
+ };
115
+ const pick = (xs, rand) => xs[Math.floor(rand() * xs.length) % xs.length];
116
+ /**
117
+ * 一个电脑对一件事的反应,没有就是 null。被扔:bot 是被扔的那个;名场面:调用方把每个电脑都问一遍(每手有上限,按问的顺序先到先得)。
118
+ * 被扔时的回应不占"每手主动互动"的次数,只守 minGapMs 和回敬上限。
119
+ */
120
+ export function botReact(ev, bot, st, now, rand, cfg = BOT_REACT) {
121
+ const mult = TEMPER_MULT[bot.temper];
122
+ const p = (x) => Math.min(0.95, x * mult);
123
+ if (now - (st.lastOut[bot.seat] ?? -Infinity) < cfg.minGapMs)
124
+ return null;
125
+ const delay = Math.round(cfg.delay[0] + rand() * (cfg.delay[1] - cfg.delay[0]));
126
+ const out = (a) => {
127
+ st.lastOut[bot.seat] = now;
128
+ return { from: bot.seat, delay, ...a };
129
+ };
130
+ if (ev.kind === 'hit') {
131
+ if (ev.to !== bot.seat || ev.from === bot.seat)
132
+ return null;
133
+ if (rand() >= p(cfg.respond))
134
+ return null;
135
+ const nice = ev.prop !== undefined && !DIRTY.includes(ev.prop);
136
+ const recent = (st.counters[bot.seat] ?? []).filter((t) => now - t < cfg.counterWindowMs);
137
+ st.counters[bot.seat] = recent;
138
+ if (rand() < cfg.counterShare && recent.length < cfg.counterMax) {
139
+ recent.push(now);
140
+ const prop = ev.prop ? COUNTER[ev.prop] : 'tomato';
141
+ return out({ to: ev.from, prop, mood: nice ? 'love' : 'angry', sticker: nice ? 'love' : 'angry' });
142
+ }
143
+ const mood = nice ? 'love' : pick(['angry', 'sweat'], rand);
144
+ return out({ to: ev.from, mood, sticker: pick(MOOD_STICKER[mood], rand) });
145
+ }
146
+ // 名场面:新的一手从头计数
147
+ if (st.hand !== ev.hand) {
148
+ st.hand = ev.hand;
149
+ st.n = 0;
150
+ }
151
+ if (st.n >= cfg.perHand)
152
+ return null;
153
+ const lost = ev.losers.includes(bot.seat);
154
+ const won = ev.winners.includes(bot.seat);
155
+ if (lost && ev.winners.length) {
156
+ if (rand() >= p(cfg.momentLose))
157
+ return null;
158
+ st.n++;
159
+ const to = ev.winners[Math.floor(rand() * ev.winners.length) % ev.winners.length];
160
+ // 一半扔个不太狠的道具,一半冒表情加一句
161
+ if (rand() < 0.5)
162
+ return out({ to, prop: pick(['tomato', 'egg', 'slipper'], rand), mood: 'angry', sticker: 'angry' });
163
+ const mood = pick(['shock', 'cry', 'angry', 'sweat'], rand);
164
+ return out({ to, mood, sticker: pick(MOOD_STICKER[mood], rand) });
165
+ }
166
+ if (won) {
167
+ if (rand() >= p(cfg.momentWin))
168
+ return null;
169
+ st.n++;
170
+ return out({ mood: 'smug', sticker: pick(MOOD_STICKER.smug, rand) });
171
+ }
172
+ return null;
173
+ }
174
+ const overlap = (a, b) => Math.max(0, Math.min(a.left + a.width, b.left + b.width) - Math.max(a.left, b.left)) * Math.max(0, Math.min(a.top + a.height, b.top + b.height) - Math.max(a.top, b.top));
175
+ /**
176
+ * 菜单(w×h)贴着头像(anchor)放:先试朝屏幕中心那一侧,再试另外三侧;夹在可见区里(留 margin),
177
+ * 和"禁区"(手牌、操作按钮)以及头像本身压得最少的那个位置胜出,一样少时按试的顺序。
178
+ */
179
+ export function placeMenu(anchor, w, h, view, avoid = [], margin = 8, gap = 10) {
180
+ const cx = anchor.left + anchor.width / 2;
181
+ const cy = anchor.top + anchor.height / 2;
182
+ const right = { left: anchor.left + anchor.width + gap, top: cy - h / 2 };
183
+ const left = { left: anchor.left - gap - w, top: cy - h / 2 };
184
+ const below = { left: cx - w / 2, top: anchor.top + anchor.height + gap };
185
+ const above = { left: cx - w / 2, top: anchor.top - gap - h };
186
+ // 朝中心:水平离中心远就先左右,否则先上下
187
+ const dx = view.width / 2 - cx;
188
+ const dy = view.height / 2 - cy;
189
+ const order = Math.abs(dx) / view.width >= Math.abs(dy) / view.height ? (dx >= 0 ? [right, below, above, left] : [left, below, above, right]) : dy >= 0 ? [below, right, left, above] : [above, right, left, below];
190
+ const clamp = (p) => ({
191
+ left: Math.max(margin, Math.min(view.width - margin - w, p.left)),
192
+ top: Math.max(margin, Math.min(view.height - margin - h, p.top)),
193
+ width: w,
194
+ height: h,
195
+ });
196
+ let best = null;
197
+ let bestCost = Infinity;
198
+ for (const c of order.map(clamp)) {
199
+ const cost = [anchor, ...avoid].reduce((s, b) => s + overlap(c, b), 0);
200
+ if (cost < bestCost) {
201
+ best = c;
202
+ bestCost = cost;
203
+ if (cost === 0)
204
+ break;
205
+ }
206
+ }
207
+ return { left: best.left, top: best.top };
208
+ }
209
+ // ---------- 编号 ----------
210
+ /**
211
+ * 编号怎么排(和房间转发的 emote id 一致):短语 0..P-1,表情 P..P+11,道具 P+12..P+19。P 是游戏短语表的长度。
212
+ * 游戏的 RoomGame.emotes 写 funIdCount(P)。
213
+ */
214
+ export function funIdCount(phrases) {
215
+ return phrases + 12 + 8;
216
+ }
217
+ export function funItem(id, phrases) {
218
+ if (!Number.isInteger(id) || id < 0 || id >= funIdCount(phrases))
219
+ return null;
220
+ if (id < phrases)
221
+ return { kind: 'phrase', index: id };
222
+ if (id < phrases + 12)
223
+ return { kind: 'sticker', index: id - phrases };
224
+ return { kind: 'prop', index: id - phrases - 12 };
225
+ }
226
+ export const stickerId = (phrases, index) => phrases + index;
227
+ export const propId = (phrases, index) => phrases + 12 + index;
228
+ /** 电脑的表情对应的情绪(页面收到电脑的表情时配一句话用);不是情绪表情的回 null */
229
+ export function stickerMood(s) {
230
+ for (const [mood, list] of Object.entries(MOOD_STICKER))
231
+ if (list.includes(s))
232
+ return mood;
233
+ return null;
234
+ }
235
+ /** 房间用:真人发来的编号换成给 botReact 的"被扔"(冲人来的道具、点名短语才算,表情、不点名的短语不算) */
236
+ export function hitEvent(id, phrases, from, to) {
237
+ const it = funItem(id, phrases);
238
+ if (!it || to === undefined || to === from || it.kind === 'sticker')
239
+ return null;
240
+ return it.kind === 'prop' ? { kind: 'hit', from, to, prop: PROPS[it.index] } : { kind: 'hit', from, to };
241
+ }
242
+ /** 房间用:电脑的反应换成要经 botEmote 发的编号。先表情(页面会配上一句话),回扔时再加道具 */
243
+ export function botEmoteIds(a, phrases) {
244
+ const out = [{ id: stickerId(phrases, STICKERS.indexOf(a.sticker)) }];
245
+ if (a.prop && a.to !== undefined)
246
+ out.push({ id: propId(phrases, PROPS.indexOf(a.prop)), to: a.to });
247
+ return out;
248
+ }
249
+ //# sourceMappingURL=fun-logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fun-logic.js","sourceRoot":"","sources":["../src/fun-logic.ts"],"names":[],"mappings":"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"}
package/dist/fun.d.ts CHANGED
@@ -1,15 +1,3 @@
1
- /**
2
- * 好玩素材(0.7.0):表情包气泡、互动道具(扔番茄、臭鸡蛋……),浏览器里用,纯 DOM + SVG + Web Animations,不依赖任何渲染库。
3
- *
4
- * - 编号到内容的表由游戏自己定:房间只转发 emote 的 id(RoomGame.emotes 是总数),游戏按"自己的起始编号 + 下标"映射到 STICKERS、PROPS;
5
- * 这两个列表顺序固定、只往后加。kit 只管画法和动画,不知道哪个游戏、哪句话;
6
- * - 只动 transform 和 opacity(合成层完成,不触发重排),所有元素 pointer-events: none,点击穿透到下面的牌桌;
7
- * - 同一个图层同时最多 MAX_PLAYING 个效果在播,多出来的直接丢掉(返回 false);同一个头像上的污渍最多叠 MAX_STAINS 层,再多先去掉最早的;
8
- * - 声音不在这里放:throwAt 在起飞、引信、命中时调 opts.sound(prop, phase),游戏用自己的音频(跟着静音开关)去放,
9
- * 配方是 playFunSound(WebAudio 现场合成);
10
- * - 被扔的头像抖一下由游戏做(头像在游戏的画布或 DOM 里,kit 碰不到):命中时调 opts.onHit(prop)。
11
- * 这个文件引用 DOM,但只在调用时才碰:在 workerd、Node 里 import 不会出错(测试只测纯函数和素材)。
12
- */
13
1
  import { PROPS, STICKERS, propSvg, stickerSvg, type PropId, type StickerId } from './fun-art.js';
14
2
  export { PROPS, STICKERS, propSvg, stickerSvg, type PropId, type StickerId };
15
3
  /** 同一个图层同时最多几个效果在播 */
@@ -75,7 +63,7 @@ export declare function playingCount(layer: FunLayer): number;
75
63
  */
76
64
  export declare function showSticker(layer: FunLayer, rect: RectLike, id: StickerId): Promise<boolean>;
77
65
  /**
78
- * 从 from(发的人头像的屏幕矩形)扔到 to(对象头像),命中后按道具播效果,污渍留 1.5–2 秒再淡出。
66
+ * 从 from(发的人头像的屏幕矩形)扔到 to(对象头像),命中后按道具播效果,脏东西的污渍留 3 秒(FUN_TIMING.stainMs)再淡出,玫瑰停 1.6 秒。
79
67
  * 名额满了直接返回 false;播完(不含污渍的停留)返回 true。
80
68
  */
81
69
  export declare function throwAt(layer: FunLayer, from: RectLike, to: RectLike, prop: PropId, opts?: ThrowOptions): Promise<boolean>;
package/dist/fun.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fun.d.ts","sourceRoot":"","sources":["../src/fun.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAsB,KAAK,EAAiD,QAAQ,EAAc,OAAO,EAAY,UAAU,EAAE,KAAK,MAAM,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE1L,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,KAAK,SAAS,EAAE,CAAC;AAE7E,sBAAsB;AACtB,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,qBAAqB;AACrB,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,yDAAyD;AACzD,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,0DAA0D;IAC1D,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,oBAAoB;IACpB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAahE;AAED,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5C,4BAA4B;IAC5B,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAID,MAAM,WAAW,EAAE;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,EAAE,EAAE,CAStE;AAED,iCAAiC;AACjC,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,GAAG;IAAE,CAAC,EAAE,EAAE,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAEtE;AAkBD,oBAAoB;AACpB,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAEpD;AA2ED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBlG;AAQD;;;GAGG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgCpI;AAwTD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,SAAI,GAAG,IAAI,CA8C/G"}
1
+ {"version":3,"file":"fun.d.ts","sourceRoot":"","sources":["../src/fun.ts"],"names":[],"mappings":"AAaA,OAAO,EAAsB,KAAK,EAAiD,QAAQ,EAAc,OAAO,EAAY,UAAU,EAAE,KAAK,MAAM,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE1L,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,KAAK,SAAS,EAAE,CAAC;AAE7E,sBAAsB;AACtB,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,qBAAqB;AACrB,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,yDAAyD;AACzD,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,0DAA0D;IAC1D,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,oBAAoB;IACpB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAahE;AAED,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5C,4BAA4B;IAC5B,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAID,MAAM,WAAW,EAAE;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,EAAE,EAAE,CAStE;AAED,iCAAiC;AACjC,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,GAAG;IAAE,CAAC,EAAE,EAAE,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAEtE;AAkBD,oBAAoB;AACpB,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAEpD;AA2ED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBlG;AAQD;;;GAGG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgCpI;AAwTD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,SAAI,GAAG,IAAI,CA8C/G"}