diff --git a/AGENTS.md b/AGENTS.md index a6afbc5..03b8921 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -58,6 +58,11 @@ - 所有技能投射物(Missiles)、次生爆炸(Explosions)、状态光环与法术特效,必须严格以 1.13c 原版 MPQ(`d2data.mpq` / `d2exp.mpq` / `Patch_D2.mpq`)中由 `Missiles.txt` 的 `CelFile` 字段所引用的原版 DCC / DC6 动画文件为准(例如 `Firebolt.dcc`, `Fireball.dcc`, `FireArrowExplode2.dcc` 等)。 - 必须通过离线解包烘焙脚本(如 `scripts/pack-missiles.ts`)结合章节调色板(`ACT1/pal.pl2`),将原版 DCC/DC6 的全部朝向(如 16 方向)与全帧序列预打包烘焙为 Web 原生 Sprite Atlas(图集)及对应元数据,供前端 WebGL 运行时直接高效索引与渲染。 - 音效接入解耦:现阶段音效系统(`Sounds.txt` / WAV 音频资源)允许暂缓接入,但视觉动画必须具备 100% 像素级原版 DCC 贴图资产与帧率对齐。 +4. **法术投射物透明度与黑边消除铁律 (Missile Transparency & Additive Blending Parity)**: + - 依据 1.13c `Missiles.txt`,所有魔法投射物与爆炸(除普通物理箭矢 `arrow` 外)均声明 `Trans: 1`(Alpha / Additive 加法半透明)。 + - MPQ 原版 DCC 动画帧在提取时背景或抗锯齿过渡区存在深黑底色(如调色板索引 172 对应 RGB `(4, 4, 4)`)。若直接生成仅以索引 0 透明的调色板 PNG 并使用标准混合渲染,会在画面上产生明显的黑色方框或黑色毛边瑕疵(Issue #385)。 + - **材质级透明处理**:投射物图集必须离线烘焙为 32-bit RGBA PNG(`colorType = 6`),且对 `Trans: 1` 法术图集严格执行零黑边过滤——凡底色或暗色过渡像素(`max(r, g, b) <= 4`)其 Alpha 通道必须强行置为 0,暗部边缘平滑过渡,确保图集中非透明黑像素数量严格为 0。 + - **着色器级混合模式**:WebGL `SpriteRenderer` 必须支持并采用加法混合(`blendMode: 'additive'`,即 `gl.blendFunc(gl.SRC_ALPHA, gl.ONE)`),实现法术发光光晕叠加与 100% 零黑边渲染;普通物理投射物(`Trans: 0`)采用常规 Alpha 混合(`gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA`)。 --- @@ -68,3 +73,17 @@ 2. **严苛静态类型与全量单测**: - `npm run typecheck` 必须保持 **0 errors**。 - `npx vitest run` 必须保持全量套件 100% 通过(包括 `global-dt1-load.test.ts`, `iso-spawn-void-guard.test.ts`, `variant-distribution.test.ts`, `superuniques-fidelity.test.ts` 等防退化单测)。 + +--- + +## 6. 斜视角与地图物理坐标 vs 渲染图标铁律 (Isometric Perspective & Coordinate Disambiguation) + +1. **2:1 斜视角投影下地面圆形的几何特征 (2:1 Isometric Projection Parity)**: + - 暗黑破坏神 2 采用 2:1 二等角投影(Isometric / Dimetric Projection,菱形单元格宽 80、高 40,子图元 Sub-tile 宽 16、高 8,垂直/水平轴比 `ISO_GROUND_ASPECT_RATIO = 0.5`)。 + - 任何在游戏世界地面平面(Ground Plane)上的圆形或径向扩张技能(如祝福之槌 Blessed Hammer 的阿基米德螺旋线、剧毒新星 Poison Nova 的 360 度圆环扩散、法术爆炸范围 AoE 伤害判定等),在投影到场景/屏幕像素坐标空间时,其几何形态在视觉上**绝对是椭圆**(长轴为水平 $X$,短轴为垂直 $Y$,且短半轴长为长半轴长的 $0.5$ 倍)。 + - 严禁在场景坐标中使用各向同性的 1:1 正圆公式计算地面运动轨迹,否则在视觉上会呈现出立在镜头正前方的“空中竖立圆圈”,与 2:1 倾斜地貌产生严重透视断层。 +2. **地图物理坐标与渲染图标严格区分 (Map Coordinates vs. Rendered Sprite Icons)**: + - **地图物理坐标(Map / World Simulation Coordinates)**:`projectile.x`, `projectile.y` 以及速度向量 `vx, vy` 计算出的是投射物在地图平面上的物理世界坐标,负责与怪物碰撞盒、地形阻挡掩码(`COLLIDE_MASK_MISSILE`)进行物理检测与命中判定。 + - **渲染图标(Rendered Sprite Billboard)**:投射物的视觉图元是基于原版 DCC 导出的 2.5D 公告板(Billboard),其在渲染时由 `drawMissileProjectile` 通过 `shot.x + frame.anchorX`, `shot.y + frame.anchorY` 锚点对齐绘制,并依据切线速度向量 `(vx, vy)` 的朝向动态选取 16/32 方向的 DCC 预烘焙视角图。 + - **严禁混淆两者的职责**:绝对禁止通过拉伸/变形渲染图标去强行模拟椭圆,也绝对禁止把渲染图标的像素尺寸误当作物理坐标。渲染图标保持原版 DCC 原始比例,而物理轨迹坐标严格遵循 2:1 地面椭圆数学方程。 + diff --git a/docs/issue-386-cast-overlay-spec.md b/docs/issue-386-cast-overlay-spec.md new file mode 100644 index 0000000..2fbce14 --- /dev/null +++ b/docs/issue-386-cast-overlay-spec.md @@ -0,0 +1,92 @@ +## 暗黑破坏神 II (v1.13c) 施法视觉效果 (Cast Overlay) 底层调查与实现设计规范 + +### 一、 机制调查与 1.13c 真实底层数据 (Ground Truth Invariant) + +在暗黑破坏神 II v1.13c 引擎体系(`D2Common.dll`、`D2Client.dll`)中,释放法术时角色脚下涌现并包裹全身的动画效果并非角色自身动作(Action Frame)或飞弹(Missile),而是属于 **Unit Overlay(单位覆盖动画系统)**。 + +#### 1. 数据驱动关系 +1. **`Skills.txt`**:包含列 **`castoverlay`**,定义技能施展时触发的覆盖效果标识(例如技能 36 火弹绑定 `fire_cast_1`)。 +2. **`Overlay.txt`**:集中定义所有覆盖效果的物理与渲染属性: + - **`Filename`**:指向 DCC 动画资源路径(位于 `d2data.mpq: data/global/overlays/{Filename}.dcc`)。 + - **`Frames`**:动画总帧数。 + - **`AnimRate`**:动画播放速率。法术施法特效原版均为 **16**(代表在 25 FPS 逻辑刻下,每 25 tick 播放 16 帧动画,即步长 `16 / 25 = 0.64` 帧/刻,总时长约 0.88 秒)。 + - **`Trans`**:混合渲染模式。原版为 **3**(**Additive Blending / 增色叠加混合**),呈现火焰、电光与寒冰的自发光半透明视觉质感。 + - **`PreDraw`**:渲染层级。原版均为 **0**(**Foreground / 前景层**),先绘制施法者角色精灵,再在前景叠加该 Overlay,形成火焰包裹躯干的立体层次。 + - **`Xoffset` / `Yoffset` / `Height1..4`**:均为 **0**,严格以施法者单位脚底地面中心点 `(0, 0)` 为基准。 + - **`InitRadius` / `Radius` / `Red, Green, Blue`**:动态点光源参数(半径均为 9 个子网格)。Overlay 激活期间会在角色周围投射对应属性的动态光晕。 + +--- + +### 二、 核心法术原版 Overlay 映射与 DCC 规格表 + +经解析 `samples/d2/Patch_D2.mpq` 与 `d2data.mpq`,法师三大元素系法术完整映射如下: + +| 技能类别 | 技能名称 (Id) | `Skills.txt` `castoverlay` | DCC 文件名 (`data/global/overlays/`) | 帧数 | DCC 碰撞盒 (Left, Top, W, H) | 光照颜色 (R, G, B, Radius) | 视觉特征 | +| :--- | :--- | :--- | :--- | :---: | :--- | :--- | :--- | +| **火焰系** | **火弹 Fire Bolt (36)** | `fire_cast_1` | `FireCast_for_Sorceress.dcc` | 14 | `[-55, -127, 117, 164]` | (255, 178, 64, 9) | **从脚底升腾直窜头顶的火焰柱 (即 Issue 附件效果)** | +| **火焰系** | 火球 (47), 强化/火焰强化 (46), 火墙 (51), 陨石 (56), 九头海蛇 (62) | `fire_cast_2` | `FireCast2.dcc` | 16 | `[-74, -89, 145, 133]` | (255, 178, 64, 9) | 范围更大、旋转包裹的炽热烈焰 | +| **冰霜系** | 冰弹 (39), 冰封甲 (40), 冰风暴 (45) | `ice_cast_1` | `IceCastNew01.dcc` | 15 | `[-49, -90, 97, 55]` | (81, 81, 255, 9) | 脚下微弱旋起的寒冰碎屑与白霜冷雾 | +| **冰霜系** | 霜之新星 (44), 碎冰甲 (50), 冰尖柱 (55) | `ice_cast_2` | `IceCastNew02.dcc` | 15 | `[-58, -100, 115, 123]` | (81, 81, 255, 9) | 向上旋转升腾的深蓝冰柱与霜雾 | +| **冰霜系** | 暴风雪 (59), 寒冰甲 (60), 冰封球 (64) | `ice_cast_3` | `IceCastNew03.dcc` | 16 | `[-63, -113, 127, 148]` | (81, 81, 255, 9) | 强烈的暴风雪霜华与立体冰凌环绕 | +| **闪电系** | 充能弹 (38), 静电场 (42), 新星 (48), 闪电 (49), 连锁闪电 (53) | `light_cast_1` | `LightningCast.dcc` | 10 | `[-79, -107, 164, 144]` | (255, 255, 255, 9) | 脚底向外炸裂并包裹全身的电弧跳跃 | +| **闪电系** | 心灵传动 (43), 雷云风暴 (57), 能量护盾 (58) | `light_cast_2` | `LightningCastRunesFront.dcc` | 10 | `[-73, -154, 147, 190]` | (255, 255, 255, 9) | 闪电符文闪耀与高耸电光柱 | +| **特殊** | 传送 Teleport (54) | `teleport` | `Teleport.dcc` | 18 | `[-61, -108, 136, 154]` | (255, 255, 200, 5) | 金黄色空间坍缩与残影粒子 | + +--- + +### 三、 系统架构与实现方案 (diablo2-web) + +遵循项目 **Zero Runtime MPQ Invariant** 及 **Anti-Silent Failures** 原则: + +#### 1. 离线资源烘焙流水线 (`scripts/pack-overlays.ts`) +- 提取 `d2data.mpq` 中上述 8 个关键施法 Overlay DCC 精灵文件。 +- 读取 `data/global/palette/ACT1/pal.pl2` 进行真实调色板色彩映射。 +- 将单向动画打包成 PNG 纹理图集并导出 JSON 元数据至 `public/overlays/` 与 `samples/d2-packs/overlays/`。 +- 自动生成类型定义 `src/render/overlays-meta.ts`,提供精确的 `box.left, box.top, width, height, animRate, trans` 常量。 + +#### 2. 运行时数据契约与实体抽象 (`src/game/skills.ts` & `src/game/engine.ts`) +- 扩展 `SkillDef` 接口,包含 `castOverlay?: string`。 +- 建立 `CANONICAL_113C_OVERLAYS` 真值表,包含 overlay 标识到对应资源与物理属性的映射。 +- 在 `GameEngine` 中引入 `ActiveOverlay` 活跃实体管理: + ```typescript + export interface ActiveOverlay { + readonly id: string + readonly overlayName: string + readonly casterId: string + x: number + y: number + frame: number + readonly maxFrames: number + readonly animRate: number + readonly preDraw: boolean + readonly trans: number + readonly lightRadius: number + readonly lightColor: readonly [number, number, number] + expired: boolean + } + ``` +- **生命周期规则**: + - 玩家或怪物在 `executePlayerSkillCast` 触发施法动作时,根据技能 `castoverlay` 生成 `ActiveOverlay`。 + - 每个逻辑 tick(25 FPS):`overlay.frame += overlay.animRate / 25`。 + - 当 `Math.floor(overlay.frame) >= overlay.maxFrames` 时,标记 `expired = true` 并在 tick 结束时销毁(单次播放不循环)。 + - Overlay 坐标实时同步施法者当前脚下位置 `(caster.x, caster.y)`。 + +#### 3. 渲染管线集成 (`src/scene/act-scene.ts`) +- 资源载入:通过 `loadOverlayArtMap` 预载 `overlays/*.png`。 +- 深度层级(Z-Order): + - 角色绘制完成后、飞弹绘制前,执行前景 Overlay 渲染。 +- 混合模式(Blend Mode): + - 遇到 `trans === 3`,切换 Canvas2D `ctx.globalCompositeOperation = 'lighter'` 或 WebGL Additive 混合状态,绘制完成后恢复 `source-over`。 +- 锚点投影(Anchor Projection): + - 精确应用 DCC 包围盒偏移:`drawX = overlay.x + frameMeta.anchorX`,`drawY = overlay.y + frameMeta.anchorY`。 +- 动态光照反馈: + - 在 Overlay 存活期间,将其注册为动态点光源(如火焰投射 9 码的 RGB(255, 178, 64) 暖黄光晕)。 + +--- + +### 四、 验证与回归测试策略 + +1. **表格对齐测试**:验证 `parseSkillsTxt` 与 `Skills.txt`、`Overlay.txt` 的 `castoverlay` 字段及参数完全一致。 +2. **生命周期测试**:验证 14 帧的 `fire_cast_1` 在 25 FPS 模拟下,在第 22 个 tick 精确结束并移除。 +3. **渲染与图集测试**:验证 `FireCast_for_Sorceress`、`IceCastNew01`、`LightningCast` 纹理图集无缺失、锚点边界无裁切、Additive 模式下正确渲染。 +4. **全场景稳定性**:自动化 Headless 运行,保障全 136 个关卡环境施法 Overlay 无跨法术贴图污染或未定义崩溃。 diff --git a/public/missiles/arrow.json b/public/missiles/arrow.json new file mode 100644 index 0000000..bbb0fe0 --- /dev/null +++ b/public/missiles/arrow.json @@ -0,0 +1,331 @@ +{ + "name": "arrow", + "celFile": "Arrow", + "width": 512, + "height": 36, + "directions": 32, + "framesPerDirection": 1, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 31, + 13, + -16, + -56 + ] + ], + [ + [ + 32, + 0, + 31, + 13, + -15, + -55 + ] + ], + [ + [ + 64, + 0, + 30, + 14, + -15, + -55 + ] + ], + [ + [ + 95, + 0, + 31, + 14, + -15, + -56 + ] + ], + [ + [ + 127, + 0, + 4, + 18, + -2, + -58 + ] + ], + [ + [ + 132, + 0, + 42, + 5, + -22, + -52 + ] + ], + [ + [ + 175, + 0, + 4, + 17, + -2, + -57 + ] + ], + [ + [ + 180, + 0, + 41, + 5, + -20, + -51 + ] + ], + [ + [ + 222, + 0, + 18, + 17, + -9, + -58 + ] + ], + [ + [ + 241, + 0, + 39, + 9, + -20, + -54 + ] + ], + [ + [ + 281, + 0, + 39, + 8, + -20, + -53 + ] + ], + [ + [ + 321, + 0, + 18, + 16, + -8, + -57 + ] + ], + [ + [ + 340, + 0, + 18, + 17, + -9, + -57 + ] + ], + [ + [ + 359, + 0, + 39, + 9, + -19, + -53 + ] + ], + [ + [ + 399, + 0, + 39, + 8, + -19, + -53 + ] + ], + [ + [ + 439, + 0, + 18, + 16, + -9, + -57 + ] + ], + [ + [ + 458, + 0, + 11, + 18, + -6, + -58 + ] + ], + [ + [ + 470, + 0, + 25, + 15, + -13, + -57 + ] + ], + [ + [ + 0, + 19, + 35, + 12, + -18, + -56 + ] + ], + [ + [ + 36, + 19, + 41, + 7, + -21, + -53 + ] + ], + [ + [ + 78, + 19, + 41, + 6, + -21, + -52 + ] + ], + [ + [ + 120, + 19, + 35, + 11, + -17, + -54 + ] + ], + [ + [ + 156, + 19, + 25, + 15, + -12, + -56 + ] + ], + [ + [ + 182, + 19, + 11, + 17, + -5, + -57 + ] + ], + [ + [ + 194, + 19, + 11, + 17, + -6, + -57 + ] + ], + [ + [ + 206, + 19, + 25, + 16, + -13, + -56 + ] + ], + [ + [ + 232, + 19, + 35, + 12, + -17, + -54 + ] + ], + [ + [ + 268, + 19, + 41, + 7, + -20, + -52 + ] + ], + [ + [ + 310, + 19, + 41, + 6, + -20, + -52 + ] + ], + [ + [ + 352, + 19, + 35, + 12, + -17, + -55 + ] + ], + [ + [ + 388, + 19, + 24, + 16, + -12, + -57 + ] + ], + [ + [ + 413, + 19, + 10, + 17, + -5, + -57 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/arrow.png b/public/missiles/arrow.png new file mode 100644 index 0000000..7e5ceb5 Binary files /dev/null and b/public/missiles/arrow.png differ diff --git a/public/missiles/blessedhammer.json b/public/missiles/blessedhammer.json new file mode 100644 index 0000000..ee4a622 --- /dev/null +++ b/public/missiles/blessedhammer.json @@ -0,0 +1,811 @@ +{ + "name": "blessedhammer", + "celFile": "blessedhammer", + "width": 512, + "height": 192, + "directions": 16, + "framesPerDirection": 6, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 27, + 38, + -13, + -56 + ], + [ + 28, + 0, + 27, + 38, + -13, + -56 + ], + [ + 56, + 0, + 27, + 38, + -13, + -56 + ], + [ + 84, + 0, + 27, + 38, + -13, + -56 + ], + [ + 112, + 0, + 27, + 38, + -13, + -56 + ], + [ + 140, + 0, + 27, + 38, + -13, + -56 + ] + ], + [ + [ + 168, + 0, + 26, + 33, + -13, + -53 + ], + [ + 195, + 0, + 26, + 33, + -13, + -53 + ], + [ + 222, + 0, + 26, + 33, + -13, + -53 + ], + [ + 249, + 0, + 26, + 33, + -13, + -53 + ], + [ + 276, + 0, + 26, + 33, + -13, + -53 + ], + [ + 303, + 0, + 26, + 33, + -13, + -53 + ] + ], + [ + [ + 330, + 0, + 27, + 33, + -14, + -54 + ], + [ + 358, + 0, + 27, + 33, + -14, + -54 + ], + [ + 386, + 0, + 27, + 33, + -14, + -54 + ], + [ + 414, + 0, + 27, + 33, + -14, + -54 + ], + [ + 442, + 0, + 27, + 33, + -14, + -54 + ], + [ + 470, + 0, + 27, + 33, + -14, + -54 + ] + ], + [ + [ + 0, + 39, + 27, + 38, + -13, + -56 + ], + [ + 28, + 39, + 27, + 38, + -13, + -56 + ], + [ + 56, + 39, + 27, + 38, + -13, + -56 + ], + [ + 84, + 39, + 27, + 38, + -13, + -56 + ], + [ + 112, + 39, + 27, + 38, + -13, + -56 + ], + [ + 140, + 39, + 27, + 38, + -13, + -56 + ] + ], + [ + [ + 168, + 39, + 7, + 38, + -3, + -56 + ], + [ + 176, + 39, + 7, + 38, + -3, + -56 + ], + [ + 184, + 39, + 7, + 38, + -3, + -56 + ], + [ + 192, + 39, + 7, + 38, + -3, + -56 + ], + [ + 200, + 39, + 7, + 38, + -3, + -56 + ], + [ + 208, + 39, + 7, + 38, + -3, + -56 + ] + ], + [ + [ + 216, + 39, + 36, + 35, + -18, + -54 + ], + [ + 253, + 39, + 36, + 35, + -18, + -54 + ], + [ + 290, + 39, + 36, + 35, + -18, + -54 + ], + [ + 327, + 39, + 36, + 35, + -18, + -54 + ], + [ + 364, + 39, + 36, + 35, + -18, + -54 + ], + [ + 401, + 39, + 36, + 35, + -18, + -54 + ] + ], + [ + [ + 438, + 39, + 7, + 32, + -4, + -53 + ], + [ + 446, + 39, + 7, + 32, + -4, + -53 + ], + [ + 454, + 39, + 7, + 32, + -4, + -53 + ], + [ + 462, + 39, + 7, + 32, + -4, + -53 + ], + [ + 470, + 39, + 7, + 32, + -4, + -53 + ], + [ + 478, + 39, + 7, + 32, + -4, + -53 + ] + ], + [ + [ + 0, + 78, + 36, + 35, + -18, + -55 + ], + [ + 37, + 78, + 36, + 35, + -18, + -55 + ], + [ + 74, + 78, + 36, + 35, + -18, + -55 + ], + [ + 111, + 78, + 36, + 35, + -18, + -55 + ], + [ + 148, + 78, + 36, + 35, + -18, + -55 + ], + [ + 185, + 78, + 36, + 35, + -18, + -55 + ] + ], + [ + [ + 222, + 78, + 16, + 38, + -8, + -56 + ], + [ + 239, + 78, + 16, + 38, + -8, + -56 + ], + [ + 256, + 78, + 16, + 38, + -8, + -56 + ], + [ + 273, + 78, + 16, + 38, + -8, + -56 + ], + [ + 290, + 78, + 16, + 38, + -8, + -56 + ], + [ + 307, + 78, + 16, + 38, + -8, + -56 + ] + ], + [ + [ + 324, + 78, + 34, + 36, + -17, + -55 + ], + [ + 359, + 78, + 34, + 36, + -17, + -55 + ], + [ + 394, + 78, + 34, + 36, + -17, + -55 + ], + [ + 429, + 78, + 34, + 36, + -17, + -55 + ], + [ + 464, + 78, + 34, + 36, + -17, + -55 + ], + [ + 0, + 117, + 34, + 36, + -17, + -55 + ] + ], + [ + [ + 35, + 117, + 34, + 34, + -17, + -54 + ], + [ + 70, + 117, + 34, + 34, + -17, + -54 + ], + [ + 105, + 117, + 34, + 34, + -17, + -54 + ], + [ + 140, + 117, + 34, + 34, + -17, + -54 + ], + [ + 175, + 117, + 34, + 34, + -17, + -54 + ], + [ + 210, + 117, + 34, + 34, + -17, + -54 + ] + ], + [ + [ + 245, + 117, + 16, + 32, + -8, + -53 + ], + [ + 262, + 117, + 16, + 32, + -8, + -53 + ], + [ + 279, + 117, + 16, + 32, + -8, + -53 + ], + [ + 296, + 117, + 16, + 32, + -8, + -53 + ], + [ + 313, + 117, + 16, + 32, + -8, + -53 + ], + [ + 330, + 117, + 16, + 32, + -8, + -53 + ] + ], + [ + [ + 347, + 117, + 16, + 32, + -9, + -53 + ], + [ + 364, + 117, + 16, + 32, + -9, + -53 + ], + [ + 381, + 117, + 16, + 32, + -9, + -53 + ], + [ + 398, + 117, + 16, + 32, + -9, + -53 + ], + [ + 415, + 117, + 16, + 32, + -9, + -53 + ], + [ + 432, + 117, + 16, + 32, + -9, + -53 + ] + ], + [ + [ + 449, + 117, + 33, + 34, + -17, + -54 + ], + [ + 0, + 154, + 33, + 34, + -17, + -54 + ], + [ + 34, + 154, + 33, + 34, + -17, + -54 + ], + [ + 68, + 154, + 33, + 34, + -17, + -54 + ], + [ + 102, + 154, + 33, + 34, + -17, + -54 + ], + [ + 136, + 154, + 33, + 34, + -17, + -54 + ] + ], + [ + [ + 170, + 154, + 34, + 36, + -17, + -55 + ], + [ + 205, + 154, + 34, + 36, + -17, + -55 + ], + [ + 240, + 154, + 34, + 36, + -17, + -55 + ], + [ + 275, + 154, + 34, + 36, + -17, + -55 + ], + [ + 310, + 154, + 34, + 36, + -17, + -55 + ], + [ + 345, + 154, + 34, + 36, + -17, + -55 + ] + ], + [ + [ + 380, + 154, + 16, + 38, + -7, + -56 + ], + [ + 397, + 154, + 16, + 38, + -7, + -56 + ], + [ + 414, + 154, + 16, + 38, + -7, + -56 + ], + [ + 431, + 154, + 16, + 38, + -7, + -56 + ], + [ + 448, + 154, + 16, + 38, + -7, + -56 + ], + [ + 465, + 154, + 16, + 38, + -7, + -56 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/blessedhammer.png b/public/missiles/blessedhammer.png new file mode 100644 index 0000000..87785a3 Binary files /dev/null and b/public/missiles/blessedhammer.png differ diff --git a/public/missiles/bonespear.json b/public/missiles/bonespear.json new file mode 100644 index 0000000..096a528 --- /dev/null +++ b/public/missiles/bonespear.json @@ -0,0 +1,811 @@ +{ + "name": "bonespear", + "celFile": "BoneSpear", + "width": 1024, + "height": 347, + "directions": 16, + "framesPerDirection": 6, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 57, + 57, + -28, + -68 + ], + [ + 58, + 0, + 57, + 57, + -28, + -68 + ], + [ + 116, + 0, + 57, + 57, + -28, + -68 + ], + [ + 174, + 0, + 57, + 57, + -28, + -68 + ], + [ + 232, + 0, + 57, + 57, + -28, + -68 + ], + [ + 290, + 0, + 57, + 57, + -28, + -68 + ] + ], + [ + [ + 348, + 0, + 58, + 57, + -27, + -68 + ], + [ + 407, + 0, + 58, + 57, + -27, + -68 + ], + [ + 466, + 0, + 58, + 57, + -27, + -68 + ], + [ + 525, + 0, + 58, + 57, + -27, + -68 + ], + [ + 584, + 0, + 58, + 57, + -27, + -68 + ], + [ + 643, + 0, + 58, + 57, + -27, + -68 + ] + ], + [ + [ + 702, + 0, + 60, + 57, + -31, + -68 + ], + [ + 763, + 0, + 60, + 57, + -31, + -68 + ], + [ + 824, + 0, + 60, + 57, + -31, + -68 + ], + [ + 885, + 0, + 60, + 57, + -31, + -68 + ], + [ + 946, + 0, + 60, + 57, + -31, + -68 + ], + [ + 0, + 58, + 60, + 57, + -31, + -68 + ] + ], + [ + [ + 61, + 58, + 58, + 57, + -29, + -68 + ], + [ + 120, + 58, + 58, + 57, + -29, + -68 + ], + [ + 179, + 58, + 58, + 57, + -29, + -68 + ], + [ + 238, + 58, + 58, + 57, + -29, + -68 + ], + [ + 297, + 58, + 58, + 57, + -29, + -68 + ], + [ + 356, + 58, + 58, + 57, + -29, + -68 + ] + ], + [ + [ + 415, + 58, + 57, + 57, + -28, + -68 + ], + [ + 473, + 58, + 57, + 57, + -28, + -68 + ], + [ + 531, + 58, + 57, + 57, + -28, + -68 + ], + [ + 589, + 58, + 57, + 57, + -28, + -68 + ], + [ + 647, + 58, + 57, + 57, + -28, + -68 + ], + [ + 705, + 58, + 57, + 57, + -28, + -68 + ] + ], + [ + [ + 763, + 58, + 68, + 57, + -28, + -68 + ], + [ + 832, + 58, + 68, + 57, + -28, + -68 + ], + [ + 901, + 58, + 68, + 57, + -28, + -68 + ], + [ + 0, + 116, + 68, + 57, + -28, + -68 + ], + [ + 69, + 116, + 68, + 57, + -28, + -68 + ], + [ + 138, + 116, + 68, + 57, + -28, + -68 + ] + ], + [ + [ + 207, + 116, + 56, + 57, + -27, + -68 + ], + [ + 264, + 116, + 56, + 57, + -27, + -68 + ], + [ + 321, + 116, + 56, + 57, + -27, + -68 + ], + [ + 378, + 116, + 56, + 57, + -27, + -68 + ], + [ + 435, + 116, + 56, + 57, + -27, + -68 + ], + [ + 492, + 116, + 56, + 57, + -27, + -68 + ] + ], + [ + [ + 549, + 116, + 69, + 57, + -40, + -68 + ], + [ + 619, + 116, + 69, + 57, + -40, + -68 + ], + [ + 689, + 116, + 69, + 57, + -40, + -68 + ], + [ + 759, + 116, + 69, + 57, + -40, + -68 + ], + [ + 829, + 116, + 69, + 57, + -40, + -68 + ], + [ + 899, + 116, + 69, + 57, + -40, + -68 + ] + ], + [ + [ + 0, + 174, + 57, + 57, + -28, + -68 + ], + [ + 58, + 174, + 57, + 57, + -28, + -68 + ], + [ + 116, + 174, + 57, + 57, + -28, + -68 + ], + [ + 174, + 174, + 57, + 57, + -28, + -68 + ], + [ + 232, + 174, + 57, + 57, + -28, + -68 + ], + [ + 290, + 174, + 57, + 57, + -28, + -68 + ] + ], + [ + [ + 348, + 174, + 65, + 57, + -28, + -68 + ], + [ + 414, + 174, + 65, + 57, + -28, + -68 + ], + [ + 480, + 174, + 65, + 57, + -28, + -68 + ], + [ + 546, + 174, + 65, + 57, + -28, + -68 + ], + [ + 612, + 174, + 65, + 57, + -28, + -68 + ], + [ + 678, + 174, + 65, + 57, + -28, + -68 + ] + ], + [ + [ + 744, + 174, + 66, + 57, + -28, + -68 + ], + [ + 811, + 174, + 66, + 57, + -28, + -68 + ], + [ + 878, + 174, + 66, + 57, + -28, + -68 + ], + [ + 945, + 174, + 66, + 57, + -28, + -68 + ], + [ + 0, + 232, + 66, + 57, + -28, + -68 + ], + [ + 67, + 232, + 66, + 57, + -28, + -68 + ] + ], + [ + [ + 134, + 232, + 56, + 57, + -27, + -68 + ], + [ + 191, + 232, + 56, + 57, + -27, + -68 + ], + [ + 248, + 232, + 56, + 57, + -27, + -68 + ], + [ + 305, + 232, + 56, + 57, + -27, + -68 + ], + [ + 362, + 232, + 56, + 57, + -27, + -68 + ], + [ + 419, + 232, + 56, + 57, + -27, + -68 + ] + ], + [ + [ + 476, + 232, + 56, + 57, + -27, + -68 + ], + [ + 533, + 232, + 56, + 57, + -27, + -68 + ], + [ + 590, + 232, + 56, + 57, + -27, + -68 + ], + [ + 647, + 232, + 56, + 57, + -27, + -68 + ], + [ + 704, + 232, + 56, + 57, + -27, + -68 + ], + [ + 761, + 232, + 56, + 57, + -27, + -68 + ] + ], + [ + [ + 818, + 232, + 67, + 57, + -38, + -68 + ], + [ + 886, + 232, + 67, + 57, + -38, + -68 + ], + [ + 954, + 232, + 67, + 57, + -38, + -68 + ], + [ + 0, + 290, + 67, + 57, + -38, + -68 + ], + [ + 68, + 290, + 67, + 57, + -38, + -68 + ], + [ + 136, + 290, + 67, + 57, + -38, + -68 + ] + ], + [ + [ + 204, + 290, + 66, + 57, + -37, + -68 + ], + [ + 271, + 290, + 66, + 57, + -37, + -68 + ], + [ + 338, + 290, + 66, + 57, + -37, + -68 + ], + [ + 405, + 290, + 66, + 57, + -37, + -68 + ], + [ + 472, + 290, + 66, + 57, + -37, + -68 + ], + [ + 539, + 290, + 66, + 57, + -37, + -68 + ] + ], + [ + [ + 606, + 290, + 57, + 57, + -28, + -68 + ], + [ + 664, + 290, + 57, + 57, + -28, + -68 + ], + [ + 722, + 290, + 57, + 57, + -28, + -68 + ], + [ + 780, + 290, + 57, + 57, + -28, + -68 + ], + [ + 838, + 290, + 57, + 57, + -28, + -68 + ], + [ + 896, + 290, + 57, + 57, + -28, + -68 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/bonespear.png b/public/missiles/bonespear.png new file mode 100644 index 0000000..47307f0 Binary files /dev/null and b/public/missiles/bonespear.png differ diff --git a/public/missiles/bonespirit.json b/public/missiles/bonespirit.json new file mode 100644 index 0000000..8fd90b9 --- /dev/null +++ b/public/missiles/bonespirit.json @@ -0,0 +1,539 @@ +{ + "name": "bonespirit", + "celFile": "BoneSpirit", + "width": 2048, + "height": 499, + "directions": 8, + "framesPerDirection": 8, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 123, + 122, + -56, + -60 + ], + [ + 124, + 0, + 123, + 122, + -56, + -60 + ], + [ + 248, + 0, + 123, + 122, + -56, + -60 + ], + [ + 372, + 0, + 123, + 122, + -56, + -60 + ], + [ + 496, + 0, + 123, + 122, + -56, + -60 + ], + [ + 620, + 0, + 123, + 122, + -56, + -60 + ], + [ + 744, + 0, + 123, + 122, + -56, + -60 + ], + [ + 868, + 0, + 123, + 122, + -56, + -60 + ] + ], + [ + [ + 992, + 0, + 125, + 124, + -57, + -55 + ], + [ + 1118, + 0, + 125, + 124, + -57, + -55 + ], + [ + 1244, + 0, + 125, + 124, + -57, + -55 + ], + [ + 1370, + 0, + 125, + 124, + -57, + -55 + ], + [ + 1496, + 0, + 125, + 124, + -57, + -55 + ], + [ + 1622, + 0, + 125, + 124, + -57, + -55 + ], + [ + 1748, + 0, + 125, + 124, + -57, + -55 + ], + [ + 1874, + 0, + 125, + 124, + -57, + -55 + ] + ], + [ + [ + 0, + 125, + 126, + 124, + -69, + -55 + ], + [ + 127, + 125, + 126, + 124, + -69, + -55 + ], + [ + 254, + 125, + 126, + 124, + -69, + -55 + ], + [ + 381, + 125, + 126, + 124, + -69, + -55 + ], + [ + 508, + 125, + 126, + 124, + -69, + -55 + ], + [ + 635, + 125, + 126, + 124, + -69, + -55 + ], + [ + 762, + 125, + 126, + 124, + -69, + -55 + ], + [ + 889, + 125, + 126, + 124, + -69, + -55 + ] + ], + [ + [ + 1016, + 125, + 124, + 122, + -68, + -60 + ], + [ + 1141, + 125, + 124, + 122, + -68, + -60 + ], + [ + 1266, + 125, + 124, + 122, + -68, + -60 + ], + [ + 1391, + 125, + 124, + 122, + -68, + -60 + ], + [ + 1516, + 125, + 124, + 122, + -68, + -60 + ], + [ + 1641, + 125, + 124, + 122, + -68, + -60 + ], + [ + 1766, + 125, + 124, + 122, + -68, + -60 + ], + [ + 1891, + 125, + 124, + 122, + -68, + -60 + ] + ], + [ + [ + 0, + 250, + 123, + 121, + -62, + -61 + ], + [ + 124, + 250, + 123, + 121, + -62, + -61 + ], + [ + 248, + 250, + 123, + 121, + -62, + -61 + ], + [ + 372, + 250, + 123, + 121, + -62, + -61 + ], + [ + 496, + 250, + 123, + 121, + -62, + -61 + ], + [ + 620, + 250, + 123, + 121, + -62, + -61 + ], + [ + 744, + 250, + 123, + 121, + -62, + -61 + ], + [ + 868, + 250, + 123, + 121, + -62, + -61 + ] + ], + [ + [ + 992, + 250, + 124, + 123, + -54, + -58 + ], + [ + 1117, + 250, + 124, + 123, + -54, + -58 + ], + [ + 1242, + 250, + 124, + 123, + -54, + -58 + ], + [ + 1367, + 250, + 124, + 123, + -54, + -58 + ], + [ + 1492, + 250, + 124, + 123, + -54, + -58 + ], + [ + 1617, + 250, + 124, + 123, + -54, + -58 + ], + [ + 1742, + 250, + 124, + 123, + -54, + -58 + ], + [ + 1867, + 250, + 124, + 123, + -54, + -58 + ] + ], + [ + [ + 0, + 374, + 127, + 125, + -64, + -54 + ], + [ + 128, + 374, + 127, + 125, + -64, + -54 + ], + [ + 256, + 374, + 127, + 125, + -64, + -54 + ], + [ + 384, + 374, + 127, + 125, + -64, + -54 + ], + [ + 512, + 374, + 127, + 125, + -64, + -54 + ], + [ + 640, + 374, + 127, + 125, + -64, + -54 + ], + [ + 768, + 374, + 127, + 125, + -64, + -54 + ], + [ + 896, + 374, + 127, + 125, + -64, + -54 + ] + ], + [ + [ + 1024, + 374, + 125, + 123, + -71, + -58 + ], + [ + 1150, + 374, + 125, + 123, + -71, + -58 + ], + [ + 1276, + 374, + 125, + 123, + -71, + -58 + ], + [ + 1402, + 374, + 125, + 123, + -71, + -58 + ], + [ + 1528, + 374, + 125, + 123, + -71, + -58 + ], + [ + 1654, + 374, + 125, + 123, + -71, + -58 + ], + [ + 1780, + 374, + 125, + 123, + -71, + -58 + ], + [ + 1906, + 374, + 125, + 123, + -71, + -58 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/bonespirit.png b/public/missiles/bonespirit.png new file mode 100644 index 0000000..edd4f7a Binary files /dev/null and b/public/missiles/bonespirit.png differ diff --git a/public/missiles/bonespiritexplode.json b/public/missiles/bonespiritexplode.json new file mode 100644 index 0000000..d1d1d3a --- /dev/null +++ b/public/missiles/bonespiritexplode.json @@ -0,0 +1,117 @@ +{ + "name": "bonespiritexplode", + "celFile": "BoneSpiritExplode", + "width": 512, + "height": 569, + "directions": 1, + "framesPerDirection": 13, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 128, + 113, + -62, + -100 + ], + [ + 129, + 0, + 128, + 113, + -62, + -100 + ], + [ + 258, + 0, + 128, + 113, + -62, + -100 + ], + [ + 0, + 114, + 128, + 113, + -62, + -100 + ], + [ + 129, + 114, + 128, + 113, + -62, + -100 + ], + [ + 258, + 114, + 128, + 113, + -62, + -100 + ], + [ + 0, + 228, + 128, + 113, + -62, + -100 + ], + [ + 129, + 228, + 128, + 113, + -62, + -100 + ], + [ + 258, + 228, + 128, + 113, + -62, + -100 + ], + [ + 0, + 342, + 128, + 113, + -62, + -100 + ], + [ + 129, + 342, + 128, + 113, + -62, + -100 + ], + [ + 258, + 342, + 128, + 113, + -62, + -100 + ], + [ + 0, + 456, + 128, + 113, + -62, + -100 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/bonespiritexplode.png b/public/missiles/bonespiritexplode.png new file mode 100644 index 0000000..d242bc2 Binary files /dev/null and b/public/missiles/bonespiritexplode.png differ diff --git a/public/missiles/chargedbolt.json b/public/missiles/chargedbolt.json new file mode 100644 index 0000000..96326bc --- /dev/null +++ b/public/missiles/chargedbolt.json @@ -0,0 +1,1323 @@ +{ + "name": "chargedbolt", + "celFile": "ChargedBolt", + "width": 1024, + "height": 744, + "directions": 16, + "framesPerDirection": 10, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 58, + 58, + -31, + -33 + ], + [ + 59, + 0, + 58, + 58, + -31, + -33 + ], + [ + 118, + 0, + 58, + 58, + -31, + -33 + ], + [ + 177, + 0, + 58, + 58, + -31, + -33 + ], + [ + 236, + 0, + 58, + 58, + -31, + -33 + ], + [ + 295, + 0, + 58, + 58, + -31, + -33 + ], + [ + 354, + 0, + 58, + 58, + -31, + -33 + ], + [ + 413, + 0, + 58, + 58, + -31, + -33 + ], + [ + 472, + 0, + 58, + 58, + -31, + -33 + ], + [ + 531, + 0, + 58, + 58, + -31, + -33 + ] + ], + [ + [ + 590, + 0, + 62, + 56, + -29, + -34 + ], + [ + 653, + 0, + 62, + 56, + -29, + -34 + ], + [ + 716, + 0, + 62, + 56, + -29, + -34 + ], + [ + 779, + 0, + 62, + 56, + -29, + -34 + ], + [ + 842, + 0, + 62, + 56, + -29, + -34 + ], + [ + 905, + 0, + 62, + 56, + -29, + -34 + ], + [ + 0, + 59, + 62, + 56, + -29, + -34 + ], + [ + 63, + 59, + 62, + 56, + -29, + -34 + ], + [ + 126, + 59, + 62, + 56, + -29, + -34 + ], + [ + 189, + 59, + 62, + 56, + -29, + -34 + ] + ], + [ + [ + 252, + 59, + 67, + 77, + -28, + -41 + ], + [ + 320, + 59, + 67, + 77, + -28, + -41 + ], + [ + 388, + 59, + 67, + 77, + -28, + -41 + ], + [ + 456, + 59, + 67, + 77, + -28, + -41 + ], + [ + 524, + 59, + 67, + 77, + -28, + -41 + ], + [ + 592, + 59, + 67, + 77, + -28, + -41 + ], + [ + 660, + 59, + 67, + 77, + -28, + -41 + ], + [ + 728, + 59, + 67, + 77, + -28, + -41 + ], + [ + 796, + 59, + 67, + 77, + -28, + -41 + ], + [ + 864, + 59, + 67, + 77, + -28, + -41 + ] + ], + [ + [ + 932, + 59, + 64, + 65, + -34, + -31 + ], + [ + 0, + 137, + 64, + 65, + -34, + -31 + ], + [ + 65, + 137, + 64, + 65, + -34, + -31 + ], + [ + 130, + 137, + 64, + 65, + -34, + -31 + ], + [ + 195, + 137, + 64, + 65, + -34, + -31 + ], + [ + 260, + 137, + 64, + 65, + -34, + -31 + ], + [ + 325, + 137, + 64, + 65, + -34, + -31 + ], + [ + 390, + 137, + 64, + 65, + -34, + -31 + ], + [ + 455, + 137, + 64, + 65, + -34, + -31 + ], + [ + 520, + 137, + 64, + 65, + -34, + -31 + ] + ], + [ + [ + 585, + 137, + 65, + 63, + -32, + -33 + ], + [ + 651, + 137, + 65, + 63, + -32, + -33 + ], + [ + 717, + 137, + 65, + 63, + -32, + -33 + ], + [ + 783, + 137, + 65, + 63, + -32, + -33 + ], + [ + 849, + 137, + 65, + 63, + -32, + -33 + ], + [ + 915, + 137, + 65, + 63, + -32, + -33 + ], + [ + 0, + 203, + 65, + 63, + -32, + -33 + ], + [ + 66, + 203, + 65, + 63, + -32, + -33 + ], + [ + 132, + 203, + 65, + 63, + -32, + -33 + ], + [ + 198, + 203, + 65, + 63, + -32, + -33 + ] + ], + [ + [ + 264, + 203, + 64, + 55, + -34, + -31 + ], + [ + 329, + 203, + 64, + 55, + -34, + -31 + ], + [ + 394, + 203, + 64, + 55, + -34, + -31 + ], + [ + 459, + 203, + 64, + 55, + -34, + -31 + ], + [ + 524, + 203, + 64, + 55, + -34, + -31 + ], + [ + 589, + 203, + 64, + 55, + -34, + -31 + ], + [ + 654, + 203, + 64, + 55, + -34, + -31 + ], + [ + 719, + 203, + 64, + 55, + -34, + -31 + ], + [ + 784, + 203, + 64, + 55, + -34, + -31 + ], + [ + 849, + 203, + 64, + 55, + -34, + -31 + ] + ], + [ + [ + 914, + 203, + 62, + 62, + -31, + -32 + ], + [ + 0, + 267, + 62, + 62, + -31, + -32 + ], + [ + 63, + 267, + 62, + 62, + -31, + -32 + ], + [ + 126, + 267, + 62, + 62, + -31, + -32 + ], + [ + 189, + 267, + 62, + 62, + -31, + -32 + ], + [ + 252, + 267, + 62, + 62, + -31, + -32 + ], + [ + 315, + 267, + 62, + 62, + -31, + -32 + ], + [ + 378, + 267, + 62, + 62, + -31, + -32 + ], + [ + 441, + 267, + 62, + 62, + -31, + -32 + ], + [ + 504, + 267, + 62, + 62, + -31, + -32 + ] + ], + [ + [ + 567, + 267, + 65, + 68, + -33, + -40 + ], + [ + 633, + 267, + 65, + 68, + -33, + -40 + ], + [ + 699, + 267, + 65, + 68, + -33, + -40 + ], + [ + 765, + 267, + 65, + 68, + -33, + -40 + ], + [ + 831, + 267, + 65, + 68, + -33, + -40 + ], + [ + 897, + 267, + 65, + 68, + -33, + -40 + ], + [ + 0, + 336, + 65, + 68, + -33, + -40 + ], + [ + 66, + 336, + 65, + 68, + -33, + -40 + ], + [ + 132, + 336, + 65, + 68, + -33, + -40 + ], + [ + 198, + 336, + 65, + 68, + -33, + -40 + ] + ], + [ + [ + 264, + 336, + 58, + 60, + -30, + -33 + ], + [ + 323, + 336, + 58, + 60, + -30, + -33 + ], + [ + 382, + 336, + 58, + 60, + -30, + -33 + ], + [ + 441, + 336, + 58, + 60, + -30, + -33 + ], + [ + 500, + 336, + 58, + 60, + -30, + -33 + ], + [ + 559, + 336, + 58, + 60, + -30, + -33 + ], + [ + 618, + 336, + 58, + 60, + -30, + -33 + ], + [ + 677, + 336, + 58, + 60, + -30, + -33 + ], + [ + 736, + 336, + 58, + 60, + -30, + -33 + ], + [ + 795, + 336, + 58, + 60, + -30, + -33 + ] + ], + [ + [ + 854, + 336, + 72, + 56, + -41, + -29 + ], + [ + 927, + 336, + 72, + 56, + -41, + -29 + ], + [ + 0, + 405, + 72, + 56, + -41, + -29 + ], + [ + 73, + 405, + 72, + 56, + -41, + -29 + ], + [ + 146, + 405, + 72, + 56, + -41, + -29 + ], + [ + 219, + 405, + 72, + 56, + -41, + -29 + ], + [ + 292, + 405, + 72, + 56, + -41, + -29 + ], + [ + 365, + 405, + 72, + 56, + -41, + -29 + ], + [ + 438, + 405, + 72, + 56, + -41, + -29 + ], + [ + 511, + 405, + 72, + 56, + -41, + -29 + ] + ], + [ + [ + 584, + 405, + 72, + 56, + -29, + -33 + ], + [ + 657, + 405, + 72, + 56, + -29, + -33 + ], + [ + 730, + 405, + 72, + 56, + -29, + -33 + ], + [ + 803, + 405, + 72, + 56, + -29, + -33 + ], + [ + 876, + 405, + 72, + 56, + -29, + -33 + ], + [ + 949, + 405, + 72, + 56, + -29, + -33 + ], + [ + 0, + 462, + 72, + 56, + -29, + -33 + ], + [ + 73, + 462, + 72, + 56, + -29, + -33 + ], + [ + 146, + 462, + 72, + 56, + -29, + -33 + ], + [ + 219, + 462, + 72, + 56, + -29, + -33 + ] + ], + [ + [ + 292, + 462, + 71, + 76, + -31, + -42 + ], + [ + 364, + 462, + 71, + 76, + -31, + -42 + ], + [ + 436, + 462, + 71, + 76, + -31, + -42 + ], + [ + 508, + 462, + 71, + 76, + -31, + -42 + ], + [ + 580, + 462, + 71, + 76, + -31, + -42 + ], + [ + 652, + 462, + 71, + 76, + -31, + -42 + ], + [ + 724, + 462, + 71, + 76, + -31, + -42 + ], + [ + 796, + 462, + 71, + 76, + -31, + -42 + ], + [ + 868, + 462, + 71, + 76, + -31, + -42 + ], + [ + 940, + 462, + 71, + 76, + -31, + -42 + ] + ], + [ + [ + 0, + 539, + 61, + 63, + -28, + -34 + ], + [ + 62, + 539, + 61, + 63, + -28, + -34 + ], + [ + 124, + 539, + 61, + 63, + -28, + -34 + ], + [ + 186, + 539, + 61, + 63, + -28, + -34 + ], + [ + 248, + 539, + 61, + 63, + -28, + -34 + ], + [ + 310, + 539, + 61, + 63, + -28, + -34 + ], + [ + 372, + 539, + 61, + 63, + -28, + -34 + ], + [ + 434, + 539, + 61, + 63, + -28, + -34 + ], + [ + 496, + 539, + 61, + 63, + -28, + -34 + ], + [ + 558, + 539, + 61, + 63, + -28, + -34 + ] + ], + [ + [ + 620, + 539, + 73, + 61, + -29, + -29 + ], + [ + 694, + 539, + 73, + 61, + -29, + -29 + ], + [ + 768, + 539, + 73, + 61, + -29, + -29 + ], + [ + 842, + 539, + 73, + 61, + -29, + -29 + ], + [ + 916, + 539, + 73, + 61, + -29, + -29 + ], + [ + 0, + 603, + 73, + 61, + -29, + -29 + ], + [ + 74, + 603, + 73, + 61, + -29, + -29 + ], + [ + 148, + 603, + 73, + 61, + -29, + -29 + ], + [ + 222, + 603, + 73, + 61, + -29, + -29 + ], + [ + 296, + 603, + 73, + 61, + -29, + -29 + ] + ], + [ + [ + 370, + 603, + 62, + 63, + -34, + -33 + ], + [ + 433, + 603, + 62, + 63, + -34, + -33 + ], + [ + 496, + 603, + 62, + 63, + -34, + -33 + ], + [ + 559, + 603, + 62, + 63, + -34, + -33 + ], + [ + 622, + 603, + 62, + 63, + -34, + -33 + ], + [ + 685, + 603, + 62, + 63, + -34, + -33 + ], + [ + 748, + 603, + 62, + 63, + -34, + -33 + ], + [ + 811, + 603, + 62, + 63, + -34, + -33 + ], + [ + 874, + 603, + 62, + 63, + -34, + -33 + ], + [ + 937, + 603, + 62, + 63, + -34, + -33 + ] + ], + [ + [ + 0, + 667, + 61, + 77, + -32, + -42 + ], + [ + 62, + 667, + 61, + 77, + -32, + -42 + ], + [ + 124, + 667, + 61, + 77, + -32, + -42 + ], + [ + 186, + 667, + 61, + 77, + -32, + -42 + ], + [ + 248, + 667, + 61, + 77, + -32, + -42 + ], + [ + 310, + 667, + 61, + 77, + -32, + -42 + ], + [ + 372, + 667, + 61, + 77, + -32, + -42 + ], + [ + 434, + 667, + 61, + 77, + -32, + -42 + ], + [ + 496, + 667, + 61, + 77, + -32, + -42 + ], + [ + 558, + 667, + 61, + 77, + -32, + -42 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/chargedbolt.png b/public/missiles/chargedbolt.png new file mode 100644 index 0000000..cc4dbf9 Binary files /dev/null and b/public/missiles/chargedbolt.png differ diff --git a/public/missiles/firearrow.json b/public/missiles/firearrow.json new file mode 100644 index 0000000..c7f43fe --- /dev/null +++ b/public/missiles/firearrow.json @@ -0,0 +1,2123 @@ +{ + "name": "firearrow", + "celFile": "FireArrow", + "width": 512, + "height": 355, + "directions": 32, + "framesPerDirection": 8, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 32, + 18, + -16, + -56 + ], + [ + 33, + 0, + 32, + 18, + -16, + -56 + ], + [ + 66, + 0, + 32, + 18, + -16, + -56 + ], + [ + 99, + 0, + 32, + 18, + -16, + -56 + ], + [ + 132, + 0, + 32, + 18, + -16, + -56 + ], + [ + 165, + 0, + 32, + 18, + -16, + -56 + ], + [ + 198, + 0, + 32, + 18, + -16, + -56 + ], + [ + 231, + 0, + 32, + 18, + -16, + -56 + ] + ], + [ + [ + 264, + 0, + 32, + 20, + -16, + -56 + ], + [ + 297, + 0, + 32, + 20, + -16, + -56 + ], + [ + 330, + 0, + 32, + 20, + -16, + -56 + ], + [ + 363, + 0, + 32, + 20, + -16, + -56 + ], + [ + 396, + 0, + 32, + 20, + -16, + -56 + ], + [ + 429, + 0, + 32, + 20, + -16, + -56 + ], + [ + 462, + 0, + 32, + 20, + -16, + -56 + ], + [ + 0, + 21, + 32, + 20, + -16, + -56 + ] + ], + [ + [ + 33, + 21, + 32, + 20, + -16, + -56 + ], + [ + 66, + 21, + 32, + 20, + -16, + -56 + ], + [ + 99, + 21, + 32, + 20, + -16, + -56 + ], + [ + 132, + 21, + 32, + 20, + -16, + -56 + ], + [ + 165, + 21, + 32, + 20, + -16, + -56 + ], + [ + 198, + 21, + 32, + 20, + -16, + -56 + ], + [ + 231, + 21, + 32, + 20, + -16, + -56 + ], + [ + 264, + 21, + 32, + 20, + -16, + -56 + ] + ], + [ + [ + 297, + 21, + 32, + 19, + -16, + -57 + ], + [ + 330, + 21, + 32, + 19, + -16, + -57 + ], + [ + 363, + 21, + 32, + 19, + -16, + -57 + ], + [ + 396, + 21, + 32, + 19, + -16, + -57 + ], + [ + 429, + 21, + 32, + 19, + -16, + -57 + ], + [ + 462, + 21, + 32, + 19, + -16, + -57 + ], + [ + 0, + 42, + 32, + 19, + -16, + -57 + ], + [ + 33, + 42, + 32, + 19, + -16, + -57 + ] + ], + [ + [ + 66, + 42, + 10, + 24, + -5, + -59 + ], + [ + 77, + 42, + 10, + 24, + -5, + -59 + ], + [ + 88, + 42, + 10, + 24, + -5, + -59 + ], + [ + 99, + 42, + 10, + 24, + -5, + -59 + ], + [ + 110, + 42, + 10, + 24, + -5, + -59 + ], + [ + 121, + 42, + 10, + 24, + -5, + -59 + ], + [ + 132, + 42, + 10, + 24, + -5, + -59 + ], + [ + 143, + 42, + 10, + 24, + -5, + -59 + ] + ], + [ + [ + 154, + 42, + 41, + 10, + -22, + -52 + ], + [ + 196, + 42, + 41, + 10, + -22, + -52 + ], + [ + 238, + 42, + 41, + 10, + -22, + -52 + ], + [ + 280, + 42, + 41, + 10, + -22, + -52 + ], + [ + 322, + 42, + 41, + 10, + -22, + -52 + ], + [ + 364, + 42, + 41, + 10, + -22, + -52 + ], + [ + 406, + 42, + 41, + 10, + -22, + -52 + ], + [ + 448, + 42, + 41, + 10, + -22, + -52 + ] + ], + [ + [ + 490, + 42, + 10, + 25, + -5, + -59 + ], + [ + 501, + 42, + 10, + 25, + -5, + -59 + ], + [ + 0, + 68, + 10, + 25, + -5, + -59 + ], + [ + 11, + 68, + 10, + 25, + -5, + -59 + ], + [ + 22, + 68, + 10, + 25, + -5, + -59 + ], + [ + 33, + 68, + 10, + 25, + -5, + -59 + ], + [ + 44, + 68, + 10, + 25, + -5, + -59 + ], + [ + 55, + 68, + 10, + 25, + -5, + -59 + ] + ], + [ + [ + 66, + 68, + 41, + 10, + -19, + -52 + ], + [ + 108, + 68, + 41, + 10, + -19, + -52 + ], + [ + 150, + 68, + 41, + 10, + -19, + -52 + ], + [ + 192, + 68, + 41, + 10, + -19, + -52 + ], + [ + 234, + 68, + 41, + 10, + -19, + -52 + ], + [ + 276, + 68, + 41, + 10, + -19, + -52 + ], + [ + 318, + 68, + 41, + 10, + -19, + -52 + ], + [ + 360, + 68, + 41, + 10, + -19, + -52 + ] + ], + [ + [ + 402, + 68, + 21, + 22, + -10, + -58 + ], + [ + 424, + 68, + 21, + 22, + -10, + -58 + ], + [ + 446, + 68, + 21, + 22, + -10, + -58 + ], + [ + 468, + 68, + 21, + 22, + -10, + -58 + ], + [ + 490, + 68, + 21, + 22, + -10, + -58 + ], + [ + 0, + 94, + 21, + 22, + -10, + -58 + ], + [ + 22, + 94, + 21, + 22, + -10, + -58 + ], + [ + 44, + 94, + 21, + 22, + -10, + -58 + ] + ], + [ + [ + 66, + 94, + 38, + 14, + -20, + -54 + ], + [ + 105, + 94, + 38, + 14, + -20, + -54 + ], + [ + 144, + 94, + 38, + 14, + -20, + -54 + ], + [ + 183, + 94, + 38, + 14, + -20, + -54 + ], + [ + 222, + 94, + 38, + 14, + -20, + -54 + ], + [ + 261, + 94, + 38, + 14, + -20, + -54 + ], + [ + 300, + 94, + 38, + 14, + -20, + -54 + ], + [ + 339, + 94, + 38, + 14, + -20, + -54 + ] + ], + [ + [ + 378, + 94, + 38, + 14, + -20, + -53 + ], + [ + 417, + 94, + 38, + 14, + -20, + -53 + ], + [ + 456, + 94, + 38, + 14, + -20, + -53 + ], + [ + 0, + 117, + 38, + 14, + -20, + -53 + ], + [ + 39, + 117, + 38, + 14, + -20, + -53 + ], + [ + 78, + 117, + 38, + 14, + -20, + -53 + ], + [ + 117, + 117, + 38, + 14, + -20, + -53 + ], + [ + 156, + 117, + 38, + 14, + -20, + -53 + ] + ], + [ + [ + 195, + 117, + 21, + 23, + -10, + -58 + ], + [ + 217, + 117, + 21, + 23, + -10, + -58 + ], + [ + 239, + 117, + 21, + 23, + -10, + -58 + ], + [ + 261, + 117, + 21, + 23, + -10, + -58 + ], + [ + 283, + 117, + 21, + 23, + -10, + -58 + ], + [ + 305, + 117, + 21, + 23, + -10, + -58 + ], + [ + 327, + 117, + 21, + 23, + -10, + -58 + ], + [ + 349, + 117, + 21, + 23, + -10, + -58 + ] + ], + [ + [ + 371, + 117, + 22, + 23, + -12, + -58 + ], + [ + 394, + 117, + 22, + 23, + -12, + -58 + ], + [ + 417, + 117, + 22, + 23, + -12, + -58 + ], + [ + 440, + 117, + 22, + 23, + -12, + -58 + ], + [ + 463, + 117, + 22, + 23, + -12, + -58 + ], + [ + 486, + 117, + 22, + 23, + -12, + -58 + ], + [ + 0, + 141, + 22, + 23, + -12, + -58 + ], + [ + 23, + 141, + 22, + 23, + -12, + -58 + ] + ], + [ + [ + 46, + 141, + 38, + 14, + -18, + -53 + ], + [ + 85, + 141, + 38, + 14, + -18, + -53 + ], + [ + 124, + 141, + 38, + 14, + -18, + -53 + ], + [ + 163, + 141, + 38, + 14, + -18, + -53 + ], + [ + 202, + 141, + 38, + 14, + -18, + -53 + ], + [ + 241, + 141, + 38, + 14, + -18, + -53 + ], + [ + 280, + 141, + 38, + 14, + -18, + -53 + ], + [ + 319, + 141, + 38, + 14, + -18, + -53 + ] + ], + [ + [ + 358, + 141, + 38, + 15, + -18, + -55 + ], + [ + 397, + 141, + 38, + 15, + -18, + -55 + ], + [ + 436, + 141, + 38, + 15, + -18, + -55 + ], + [ + 0, + 165, + 38, + 15, + -18, + -55 + ], + [ + 39, + 165, + 38, + 15, + -18, + -55 + ], + [ + 78, + 165, + 38, + 15, + -18, + -55 + ], + [ + 117, + 165, + 38, + 15, + -18, + -55 + ], + [ + 156, + 165, + 38, + 15, + -18, + -55 + ] + ], + [ + [ + 195, + 165, + 22, + 23, + -12, + -59 + ], + [ + 218, + 165, + 22, + 23, + -12, + -59 + ], + [ + 241, + 165, + 22, + 23, + -12, + -59 + ], + [ + 264, + 165, + 22, + 23, + -12, + -59 + ], + [ + 287, + 165, + 22, + 23, + -12, + -59 + ], + [ + 310, + 165, + 22, + 23, + -12, + -59 + ], + [ + 333, + 165, + 22, + 23, + -12, + -59 + ], + [ + 356, + 165, + 22, + 23, + -12, + -59 + ] + ], + [ + [ + 379, + 165, + 16, + 23, + -7, + -58 + ], + [ + 396, + 165, + 16, + 23, + -7, + -58 + ], + [ + 413, + 165, + 16, + 23, + -7, + -58 + ], + [ + 430, + 165, + 16, + 23, + -7, + -58 + ], + [ + 447, + 165, + 16, + 23, + -7, + -58 + ], + [ + 464, + 165, + 16, + 23, + -7, + -58 + ], + [ + 481, + 165, + 16, + 23, + -7, + -58 + ], + [ + 0, + 189, + 16, + 23, + -7, + -58 + ] + ], + [ + [ + 17, + 189, + 27, + 20, + -13, + -57 + ], + [ + 45, + 189, + 27, + 20, + -13, + -57 + ], + [ + 73, + 189, + 27, + 20, + -13, + -57 + ], + [ + 101, + 189, + 27, + 20, + -13, + -57 + ], + [ + 129, + 189, + 27, + 20, + -13, + -57 + ], + [ + 157, + 189, + 27, + 20, + -13, + -57 + ], + [ + 185, + 189, + 27, + 20, + -13, + -57 + ], + [ + 213, + 189, + 27, + 20, + -13, + -57 + ] + ], + [ + [ + 241, + 189, + 35, + 16, + -18, + -55 + ], + [ + 277, + 189, + 35, + 16, + -18, + -55 + ], + [ + 313, + 189, + 35, + 16, + -18, + -55 + ], + [ + 349, + 189, + 35, + 16, + -18, + -55 + ], + [ + 385, + 189, + 35, + 16, + -18, + -55 + ], + [ + 421, + 189, + 35, + 16, + -18, + -55 + ], + [ + 457, + 189, + 35, + 16, + -18, + -55 + ], + [ + 0, + 213, + 35, + 16, + -18, + -55 + ] + ], + [ + [ + 36, + 213, + 41, + 11, + -22, + -53 + ], + [ + 78, + 213, + 41, + 11, + -22, + -53 + ], + [ + 120, + 213, + 41, + 11, + -22, + -53 + ], + [ + 162, + 213, + 41, + 11, + -22, + -53 + ], + [ + 204, + 213, + 41, + 11, + -22, + -53 + ], + [ + 246, + 213, + 41, + 11, + -22, + -53 + ], + [ + 288, + 213, + 41, + 11, + -22, + -53 + ], + [ + 330, + 213, + 41, + 11, + -22, + -53 + ] + ], + [ + [ + 372, + 213, + 41, + 12, + -22, + -52 + ], + [ + 414, + 213, + 41, + 12, + -22, + -52 + ], + [ + 456, + 213, + 41, + 12, + -22, + -52 + ], + [ + 0, + 230, + 41, + 12, + -22, + -52 + ], + [ + 42, + 230, + 41, + 12, + -22, + -52 + ], + [ + 84, + 230, + 41, + 12, + -22, + -52 + ], + [ + 126, + 230, + 41, + 12, + -22, + -52 + ], + [ + 168, + 230, + 41, + 12, + -22, + -52 + ] + ], + [ + [ + 210, + 230, + 35, + 18, + -18, + -55 + ], + [ + 246, + 230, + 35, + 18, + -18, + -55 + ], + [ + 282, + 230, + 35, + 18, + -18, + -55 + ], + [ + 318, + 230, + 35, + 18, + -18, + -55 + ], + [ + 354, + 230, + 35, + 18, + -18, + -55 + ], + [ + 390, + 230, + 35, + 18, + -18, + -55 + ], + [ + 426, + 230, + 35, + 18, + -18, + -55 + ], + [ + 462, + 230, + 35, + 18, + -18, + -55 + ] + ], + [ + [ + 0, + 249, + 27, + 22, + -13, + -57 + ], + [ + 28, + 249, + 27, + 22, + -13, + -57 + ], + [ + 56, + 249, + 27, + 22, + -13, + -57 + ], + [ + 84, + 249, + 27, + 22, + -13, + -57 + ], + [ + 112, + 249, + 27, + 22, + -13, + -57 + ], + [ + 140, + 249, + 27, + 22, + -13, + -57 + ], + [ + 168, + 249, + 27, + 22, + -13, + -57 + ], + [ + 196, + 249, + 27, + 22, + -13, + -57 + ] + ], + [ + [ + 224, + 249, + 16, + 24, + -7, + -58 + ], + [ + 241, + 249, + 16, + 24, + -7, + -58 + ], + [ + 258, + 249, + 16, + 24, + -7, + -58 + ], + [ + 275, + 249, + 16, + 24, + -7, + -58 + ], + [ + 292, + 249, + 16, + 24, + -7, + -58 + ], + [ + 309, + 249, + 16, + 24, + -7, + -58 + ], + [ + 326, + 249, + 16, + 24, + -7, + -58 + ], + [ + 343, + 249, + 16, + 24, + -7, + -58 + ] + ], + [ + [ + 360, + 249, + 16, + 24, + -9, + -58 + ], + [ + 377, + 249, + 16, + 24, + -9, + -58 + ], + [ + 394, + 249, + 16, + 24, + -9, + -58 + ], + [ + 411, + 249, + 16, + 24, + -9, + -58 + ], + [ + 428, + 249, + 16, + 24, + -9, + -58 + ], + [ + 445, + 249, + 16, + 24, + -9, + -58 + ], + [ + 462, + 249, + 16, + 24, + -9, + -58 + ], + [ + 479, + 249, + 16, + 24, + -9, + -58 + ] + ], + [ + [ + 0, + 274, + 27, + 22, + -14, + -57 + ], + [ + 28, + 274, + 27, + 22, + -14, + -57 + ], + [ + 56, + 274, + 27, + 22, + -14, + -57 + ], + [ + 84, + 274, + 27, + 22, + -14, + -57 + ], + [ + 112, + 274, + 27, + 22, + -14, + -57 + ], + [ + 140, + 274, + 27, + 22, + -14, + -57 + ], + [ + 168, + 274, + 27, + 22, + -14, + -57 + ], + [ + 196, + 274, + 27, + 22, + -14, + -57 + ] + ], + [ + [ + 224, + 274, + 35, + 18, + -17, + -55 + ], + [ + 260, + 274, + 35, + 18, + -17, + -55 + ], + [ + 296, + 274, + 35, + 18, + -17, + -55 + ], + [ + 332, + 274, + 35, + 18, + -17, + -55 + ], + [ + 368, + 274, + 35, + 18, + -17, + -55 + ], + [ + 404, + 274, + 35, + 18, + -17, + -55 + ], + [ + 440, + 274, + 35, + 18, + -17, + -55 + ], + [ + 476, + 274, + 35, + 18, + -17, + -55 + ] + ], + [ + [ + 0, + 297, + 41, + 12, + -19, + -52 + ], + [ + 42, + 297, + 41, + 12, + -19, + -52 + ], + [ + 84, + 297, + 41, + 12, + -19, + -52 + ], + [ + 126, + 297, + 41, + 12, + -19, + -52 + ], + [ + 168, + 297, + 41, + 12, + -19, + -52 + ], + [ + 210, + 297, + 41, + 12, + -19, + -52 + ], + [ + 252, + 297, + 41, + 12, + -19, + -52 + ], + [ + 294, + 297, + 41, + 12, + -19, + -52 + ] + ], + [ + [ + 336, + 297, + 41, + 11, + -19, + -53 + ], + [ + 378, + 297, + 41, + 11, + -19, + -53 + ], + [ + 420, + 297, + 41, + 11, + -19, + -53 + ], + [ + 462, + 297, + 41, + 11, + -19, + -53 + ], + [ + 0, + 310, + 41, + 11, + -19, + -53 + ], + [ + 42, + 310, + 41, + 11, + -19, + -53 + ], + [ + 84, + 310, + 41, + 11, + -19, + -53 + ], + [ + 126, + 310, + 41, + 11, + -19, + -53 + ] + ], + [ + [ + 168, + 310, + 35, + 17, + -17, + -56 + ], + [ + 204, + 310, + 35, + 17, + -17, + -56 + ], + [ + 240, + 310, + 35, + 17, + -17, + -56 + ], + [ + 276, + 310, + 35, + 17, + -17, + -56 + ], + [ + 312, + 310, + 35, + 17, + -17, + -56 + ], + [ + 348, + 310, + 35, + 17, + -17, + -56 + ], + [ + 384, + 310, + 35, + 17, + -17, + -56 + ], + [ + 420, + 310, + 35, + 17, + -17, + -56 + ] + ], + [ + [ + 456, + 310, + 27, + 20, + -14, + -57 + ], + [ + 484, + 310, + 27, + 20, + -14, + -57 + ], + [ + 0, + 331, + 27, + 20, + -14, + -57 + ], + [ + 28, + 331, + 27, + 20, + -14, + -57 + ], + [ + 56, + 331, + 27, + 20, + -14, + -57 + ], + [ + 84, + 331, + 27, + 20, + -14, + -57 + ], + [ + 112, + 331, + 27, + 20, + -14, + -57 + ], + [ + 140, + 331, + 27, + 20, + -14, + -57 + ] + ], + [ + [ + 168, + 331, + 16, + 24, + -9, + -59 + ], + [ + 185, + 331, + 16, + 24, + -9, + -59 + ], + [ + 202, + 331, + 16, + 24, + -9, + -59 + ], + [ + 219, + 331, + 16, + 24, + -9, + -59 + ], + [ + 236, + 331, + 16, + 24, + -9, + -59 + ], + [ + 253, + 331, + 16, + 24, + -9, + -59 + ], + [ + 270, + 331, + 16, + 24, + -9, + -59 + ], + [ + 287, + 331, + 16, + 24, + -9, + -59 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/firearrow.png b/public/missiles/firearrow.png new file mode 100644 index 0000000..dfd1bfb Binary files /dev/null and b/public/missiles/firearrow.png differ diff --git a/public/missiles/fireball.png b/public/missiles/fireball.png index 3201007..5df23f4 100644 Binary files a/public/missiles/fireball.png and b/public/missiles/fireball.png differ diff --git a/public/missiles/firebolt.png b/public/missiles/firebolt.png index 41ac3e6..ab4fcc1 100644 Binary files a/public/missiles/firebolt.png and b/public/missiles/firebolt.png differ diff --git a/public/missiles/fireexplode.png b/public/missiles/fireexplode.png index c5d5b93..dcb8372 100644 Binary files a/public/missiles/fireexplode.png and b/public/missiles/fireexplode.png differ diff --git a/public/missiles/freezeexplode.json b/public/missiles/freezeexplode.json new file mode 100644 index 0000000..8a2be10 --- /dev/null +++ b/public/missiles/freezeexplode.json @@ -0,0 +1,133 @@ +{ + "name": "freezeexplode", + "celFile": "FreezeExplodeCenter", + "width": 1024, + "height": 323, + "directions": 1, + "framesPerDirection": 15, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 143, + 107, + -75, + -67 + ], + [ + 144, + 0, + 143, + 107, + -75, + -67 + ], + [ + 288, + 0, + 143, + 107, + -75, + -67 + ], + [ + 432, + 0, + 143, + 107, + -75, + -67 + ], + [ + 576, + 0, + 143, + 107, + -75, + -67 + ], + [ + 720, + 0, + 143, + 107, + -75, + -67 + ], + [ + 864, + 0, + 143, + 107, + -75, + -67 + ], + [ + 0, + 108, + 143, + 107, + -75, + -67 + ], + [ + 144, + 108, + 143, + 107, + -75, + -67 + ], + [ + 288, + 108, + 143, + 107, + -75, + -67 + ], + [ + 432, + 108, + 143, + 107, + -75, + -67 + ], + [ + 576, + 108, + 143, + 107, + -75, + -67 + ], + [ + 720, + 108, + 143, + 107, + -75, + -67 + ], + [ + 864, + 108, + 143, + 107, + -75, + -67 + ], + [ + 0, + 216, + 143, + 107, + -75, + -67 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/freezeexplode.png b/public/missiles/freezeexplode.png new file mode 100644 index 0000000..64356ac Binary files /dev/null and b/public/missiles/freezeexplode.png differ diff --git a/public/missiles/glacialspike.json b/public/missiles/glacialspike.json new file mode 100644 index 0000000..2c3cb5b --- /dev/null +++ b/public/missiles/glacialspike.json @@ -0,0 +1,811 @@ +{ + "name": "glacialspike", + "celFile": "GlacialSpike", + "width": 1024, + "height": 719, + "directions": 16, + "framesPerDirection": 6, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 100, + 61, + -34, + -88 + ], + [ + 101, + 0, + 100, + 61, + -34, + -88 + ], + [ + 202, + 0, + 100, + 61, + -34, + -88 + ], + [ + 303, + 0, + 100, + 61, + -34, + -88 + ], + [ + 404, + 0, + 100, + 61, + -34, + -88 + ], + [ + 505, + 0, + 100, + 61, + -34, + -88 + ] + ], + [ + [ + 606, + 0, + 104, + 67, + -31, + -63 + ], + [ + 711, + 0, + 104, + 67, + -31, + -63 + ], + [ + 816, + 0, + 104, + 67, + -31, + -63 + ], + [ + 0, + 68, + 104, + 67, + -31, + -63 + ], + [ + 105, + 68, + 104, + 67, + -31, + -63 + ], + [ + 210, + 68, + 104, + 67, + -31, + -63 + ] + ], + [ + [ + 315, + 68, + 110, + 68, + -79, + -62 + ], + [ + 426, + 68, + 110, + 68, + -79, + -62 + ], + [ + 537, + 68, + 110, + 68, + -79, + -62 + ], + [ + 648, + 68, + 110, + 68, + -79, + -62 + ], + [ + 759, + 68, + 110, + 68, + -79, + -62 + ], + [ + 870, + 68, + 110, + 68, + -79, + -62 + ] + ], + [ + [ + 0, + 137, + 96, + 59, + -62, + -86 + ], + [ + 97, + 137, + 96, + 59, + -62, + -86 + ], + [ + 194, + 137, + 96, + 59, + -62, + -86 + ], + [ + 291, + 137, + 96, + 59, + -62, + -86 + ], + [ + 388, + 137, + 96, + 59, + -62, + -86 + ], + [ + 485, + 137, + 96, + 59, + -62, + -86 + ] + ], + [ + [ + 582, + 137, + 37, + 73, + -19, + -94 + ], + [ + 620, + 137, + 37, + 73, + -19, + -94 + ], + [ + 658, + 137, + 37, + 73, + -19, + -94 + ], + [ + 696, + 137, + 37, + 73, + -19, + -94 + ], + [ + 734, + 137, + 37, + 73, + -19, + -94 + ], + [ + 772, + 137, + 37, + 73, + -19, + -94 + ] + ], + [ + [ + 810, + 137, + 134, + 48, + -44, + -71 + ], + [ + 0, + 211, + 134, + 48, + -44, + -71 + ], + [ + 135, + 211, + 134, + 48, + -44, + -71 + ], + [ + 270, + 211, + 134, + 48, + -44, + -71 + ], + [ + 405, + 211, + 134, + 48, + -44, + -71 + ], + [ + 540, + 211, + 134, + 48, + -44, + -71 + ] + ], + [ + [ + 675, + 211, + 45, + 83, + -21, + -67 + ], + [ + 721, + 211, + 45, + 83, + -21, + -67 + ], + [ + 767, + 211, + 45, + 83, + -21, + -67 + ], + [ + 813, + 211, + 45, + 83, + -21, + -67 + ], + [ + 859, + 211, + 45, + 83, + -21, + -67 + ], + [ + 905, + 211, + 45, + 83, + -21, + -67 + ] + ], + [ + [ + 0, + 295, + 129, + 48, + -86, + -69 + ], + [ + 130, + 295, + 129, + 48, + -86, + -69 + ], + [ + 260, + 295, + 129, + 48, + -86, + -69 + ], + [ + 390, + 295, + 129, + 48, + -86, + -69 + ], + [ + 520, + 295, + 129, + 48, + -86, + -69 + ], + [ + 650, + 295, + 129, + 48, + -86, + -69 + ] + ], + [ + [ + 780, + 295, + 65, + 70, + -22, + -93 + ], + [ + 846, + 295, + 65, + 70, + -22, + -93 + ], + [ + 912, + 295, + 65, + 70, + -22, + -93 + ], + [ + 0, + 366, + 65, + 70, + -22, + -93 + ], + [ + 66, + 366, + 65, + 70, + -22, + -93 + ], + [ + 132, + 366, + 65, + 70, + -22, + -93 + ] + ], + [ + [ + 198, + 366, + 124, + 50, + -41, + -81 + ], + [ + 323, + 366, + 124, + 50, + -41, + -81 + ], + [ + 448, + 366, + 124, + 50, + -41, + -81 + ], + [ + 573, + 366, + 124, + 50, + -41, + -81 + ], + [ + 698, + 366, + 124, + 50, + -41, + -81 + ], + [ + 823, + 366, + 124, + 50, + -41, + -81 + ] + ], + [ + [ + 0, + 437, + 124, + 51, + -39, + -60 + ], + [ + 125, + 437, + 124, + 51, + -39, + -60 + ], + [ + 250, + 437, + 124, + 51, + -39, + -60 + ], + [ + 375, + 437, + 124, + 51, + -39, + -60 + ], + [ + 500, + 437, + 124, + 51, + -39, + -60 + ], + [ + 625, + 437, + 124, + 51, + -39, + -60 + ] + ], + [ + [ + 750, + 437, + 71, + 78, + -20, + -65 + ], + [ + 822, + 437, + 71, + 78, + -20, + -65 + ], + [ + 894, + 437, + 71, + 78, + -20, + -65 + ], + [ + 0, + 516, + 71, + 78, + -20, + -65 + ], + [ + 72, + 516, + 71, + 78, + -20, + -65 + ], + [ + 144, + 516, + 71, + 78, + -20, + -65 + ] + ], + [ + [ + 216, + 516, + 74, + 79, + -54, + -65 + ], + [ + 291, + 516, + 74, + 79, + -54, + -65 + ], + [ + 366, + 516, + 74, + 79, + -54, + -65 + ], + [ + 441, + 516, + 74, + 79, + -54, + -65 + ], + [ + 516, + 516, + 74, + 79, + -54, + -65 + ], + [ + 591, + 516, + 74, + 79, + -54, + -65 + ] + ], + [ + [ + 666, + 516, + 129, + 52, + -90, + -59 + ], + [ + 796, + 516, + 129, + 52, + -90, + -59 + ], + [ + 0, + 596, + 129, + 52, + -90, + -59 + ], + [ + 130, + 596, + 129, + 52, + -90, + -59 + ], + [ + 260, + 596, + 129, + 52, + -90, + -59 + ], + [ + 390, + 596, + 129, + 52, + -90, + -59 + ] + ], + [ + [ + 520, + 596, + 120, + 46, + -78, + -78 + ], + [ + 641, + 596, + 120, + 46, + -78, + -78 + ], + [ + 762, + 596, + 120, + 46, + -78, + -78 + ], + [ + 883, + 596, + 120, + 46, + -78, + -78 + ], + [ + 0, + 649, + 120, + 46, + -78, + -78 + ], + [ + 121, + 649, + 120, + 46, + -78, + -78 + ] + ], + [ + [ + 242, + 649, + 65, + 70, + -43, + -93 + ], + [ + 308, + 649, + 65, + 70, + -43, + -93 + ], + [ + 374, + 649, + 65, + 70, + -43, + -93 + ], + [ + 440, + 649, + 65, + 70, + -43, + -93 + ], + [ + 506, + 649, + 65, + 70, + -43, + -93 + ], + [ + 572, + 649, + 65, + 70, + -43, + -93 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/glacialspike.png b/public/missiles/glacialspike.png new file mode 100644 index 0000000..4a9c95e Binary files /dev/null and b/public/missiles/glacialspike.png differ diff --git a/public/missiles/holybolt.json b/public/missiles/holybolt.json new file mode 100644 index 0000000..f589fa3 --- /dev/null +++ b/public/missiles/holybolt.json @@ -0,0 +1,141 @@ +{ + "name": "holybolt", + "celFile": "HolyBoltMissile", + "width": 512, + "height": 137, + "directions": 1, + "framesPerDirection": 16, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 79, + 45, + -39, + -59 + ], + [ + 80, + 0, + 79, + 45, + -39, + -59 + ], + [ + 160, + 0, + 79, + 45, + -39, + -59 + ], + [ + 240, + 0, + 79, + 45, + -39, + -59 + ], + [ + 320, + 0, + 79, + 45, + -39, + -59 + ], + [ + 400, + 0, + 79, + 45, + -39, + -59 + ], + [ + 0, + 46, + 79, + 45, + -39, + -59 + ], + [ + 80, + 46, + 79, + 45, + -39, + -59 + ], + [ + 160, + 46, + 79, + 45, + -39, + -59 + ], + [ + 240, + 46, + 79, + 45, + -39, + -59 + ], + [ + 320, + 46, + 79, + 45, + -39, + -59 + ], + [ + 400, + 46, + 79, + 45, + -39, + -59 + ], + [ + 0, + 92, + 79, + 45, + -39, + -59 + ], + [ + 80, + 92, + 79, + 45, + -39, + -59 + ], + [ + 160, + 92, + 79, + 45, + -39, + -59 + ], + [ + 240, + 92, + 79, + 45, + -39, + -59 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/holybolt.png b/public/missiles/holybolt.png new file mode 100644 index 0000000..5cc3b14 Binary files /dev/null and b/public/missiles/holybolt.png differ diff --git a/public/missiles/icearrow.json b/public/missiles/icearrow.json new file mode 100644 index 0000000..e51573f --- /dev/null +++ b/public/missiles/icearrow.json @@ -0,0 +1,2123 @@ +{ + "name": "icearrow", + "celFile": "IceArrow", + "width": 1024, + "height": 324, + "directions": 32, + "framesPerDirection": 8, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 45, + 25, + -20, + -60 + ], + [ + 46, + 0, + 45, + 25, + -20, + -60 + ], + [ + 92, + 0, + 45, + 25, + -20, + -60 + ], + [ + 138, + 0, + 45, + 25, + -20, + -60 + ], + [ + 184, + 0, + 45, + 25, + -20, + -60 + ], + [ + 230, + 0, + 45, + 25, + -20, + -60 + ], + [ + 276, + 0, + 45, + 25, + -20, + -60 + ], + [ + 322, + 0, + 45, + 25, + -20, + -60 + ] + ], + [ + [ + 368, + 0, + 44, + 25, + -19, + -58 + ], + [ + 413, + 0, + 44, + 25, + -19, + -58 + ], + [ + 458, + 0, + 44, + 25, + -19, + -58 + ], + [ + 503, + 0, + 44, + 25, + -19, + -58 + ], + [ + 548, + 0, + 44, + 25, + -19, + -58 + ], + [ + 593, + 0, + 44, + 25, + -19, + -58 + ], + [ + 638, + 0, + 44, + 25, + -19, + -58 + ], + [ + 683, + 0, + 44, + 25, + -19, + -58 + ] + ], + [ + [ + 728, + 0, + 45, + 25, + -25, + -58 + ], + [ + 774, + 0, + 45, + 25, + -25, + -58 + ], + [ + 820, + 0, + 45, + 25, + -25, + -58 + ], + [ + 866, + 0, + 45, + 25, + -25, + -58 + ], + [ + 912, + 0, + 45, + 25, + -25, + -58 + ], + [ + 958, + 0, + 45, + 25, + -25, + -58 + ], + [ + 0, + 26, + 45, + 25, + -25, + -58 + ], + [ + 46, + 26, + 45, + 25, + -25, + -58 + ] + ], + [ + [ + 92, + 26, + 45, + 24, + -25, + -60 + ], + [ + 138, + 26, + 45, + 24, + -25, + -60 + ], + [ + 184, + 26, + 45, + 24, + -25, + -60 + ], + [ + 230, + 26, + 45, + 24, + -25, + -60 + ], + [ + 276, + 26, + 45, + 24, + -25, + -60 + ], + [ + 322, + 26, + 45, + 24, + -25, + -60 + ], + [ + 368, + 26, + 45, + 24, + -25, + -60 + ], + [ + 414, + 26, + 45, + 24, + -25, + -60 + ] + ], + [ + [ + 460, + 26, + 16, + 31, + -8, + -64 + ], + [ + 477, + 26, + 16, + 31, + -8, + -64 + ], + [ + 494, + 26, + 16, + 31, + -8, + -64 + ], + [ + 511, + 26, + 16, + 31, + -8, + -64 + ], + [ + 528, + 26, + 16, + 31, + -8, + -64 + ], + [ + 545, + 26, + 16, + 31, + -8, + -64 + ], + [ + 562, + 26, + 16, + 31, + -8, + -64 + ], + [ + 579, + 26, + 16, + 31, + -8, + -64 + ] + ], + [ + [ + 596, + 26, + 61, + 15, + -27, + -54 + ], + [ + 658, + 26, + 61, + 15, + -27, + -54 + ], + [ + 720, + 26, + 61, + 15, + -27, + -54 + ], + [ + 782, + 26, + 61, + 15, + -27, + -54 + ], + [ + 844, + 26, + 61, + 15, + -27, + -54 + ], + [ + 906, + 26, + 61, + 15, + -27, + -54 + ], + [ + 0, + 58, + 61, + 15, + -27, + -54 + ], + [ + 62, + 58, + 61, + 15, + -27, + -54 + ] + ], + [ + [ + 124, + 58, + 16, + 32, + -8, + -61 + ], + [ + 141, + 58, + 16, + 32, + -8, + -61 + ], + [ + 158, + 58, + 16, + 32, + -8, + -61 + ], + [ + 175, + 58, + 16, + 32, + -8, + -61 + ], + [ + 192, + 58, + 16, + 32, + -8, + -61 + ], + [ + 209, + 58, + 16, + 32, + -8, + -61 + ], + [ + 226, + 58, + 16, + 32, + -8, + -61 + ], + [ + 243, + 58, + 16, + 32, + -8, + -61 + ] + ], + [ + [ + 260, + 58, + 60, + 15, + -34, + -54 + ], + [ + 321, + 58, + 60, + 15, + -34, + -54 + ], + [ + 382, + 58, + 60, + 15, + -34, + -54 + ], + [ + 443, + 58, + 60, + 15, + -34, + -54 + ], + [ + 504, + 58, + 60, + 15, + -34, + -54 + ], + [ + 565, + 58, + 60, + 15, + -34, + -54 + ], + [ + 626, + 58, + 60, + 15, + -34, + -54 + ], + [ + 687, + 58, + 60, + 15, + -34, + -54 + ] + ], + [ + [ + 748, + 58, + 27, + 30, + -12, + -63 + ], + [ + 776, + 58, + 27, + 30, + -12, + -63 + ], + [ + 804, + 58, + 27, + 30, + -12, + -63 + ], + [ + 832, + 58, + 27, + 30, + -12, + -63 + ], + [ + 860, + 58, + 27, + 30, + -12, + -63 + ], + [ + 888, + 58, + 27, + 30, + -12, + -63 + ], + [ + 916, + 58, + 27, + 30, + -12, + -63 + ], + [ + 944, + 58, + 27, + 30, + -12, + -63 + ] + ], + [ + [ + 0, + 91, + 57, + 19, + -25, + -57 + ], + [ + 58, + 91, + 57, + 19, + -25, + -57 + ], + [ + 116, + 91, + 57, + 19, + -25, + -57 + ], + [ + 174, + 91, + 57, + 19, + -25, + -57 + ], + [ + 232, + 91, + 57, + 19, + -25, + -57 + ], + [ + 290, + 91, + 57, + 19, + -25, + -57 + ], + [ + 348, + 91, + 57, + 19, + -25, + -57 + ], + [ + 406, + 91, + 57, + 19, + -25, + -57 + ] + ], + [ + [ + 464, + 91, + 57, + 18, + -25, + -55 + ], + [ + 522, + 91, + 57, + 18, + -25, + -55 + ], + [ + 580, + 91, + 57, + 18, + -25, + -55 + ], + [ + 638, + 91, + 57, + 18, + -25, + -55 + ], + [ + 696, + 91, + 57, + 18, + -25, + -55 + ], + [ + 754, + 91, + 57, + 18, + -25, + -55 + ], + [ + 812, + 91, + 57, + 18, + -25, + -55 + ], + [ + 870, + 91, + 57, + 18, + -25, + -55 + ] + ], + [ + [ + 928, + 91, + 27, + 30, + -12, + -60 + ], + [ + 956, + 91, + 27, + 30, + -12, + -60 + ], + [ + 984, + 91, + 27, + 30, + -12, + -60 + ], + [ + 0, + 122, + 27, + 30, + -12, + -60 + ], + [ + 28, + 122, + 27, + 30, + -12, + -60 + ], + [ + 56, + 122, + 27, + 30, + -12, + -60 + ], + [ + 84, + 122, + 27, + 30, + -12, + -60 + ], + [ + 112, + 122, + 27, + 30, + -12, + -60 + ] + ], + [ + [ + 140, + 122, + 27, + 30, + -15, + -60 + ], + [ + 168, + 122, + 27, + 30, + -15, + -60 + ], + [ + 196, + 122, + 27, + 30, + -15, + -60 + ], + [ + 224, + 122, + 27, + 30, + -15, + -60 + ], + [ + 252, + 122, + 27, + 30, + -15, + -60 + ], + [ + 280, + 122, + 27, + 30, + -15, + -60 + ], + [ + 308, + 122, + 27, + 30, + -15, + -60 + ], + [ + 336, + 122, + 27, + 30, + -15, + -60 + ] + ], + [ + [ + 364, + 122, + 57, + 18, + -32, + -55 + ], + [ + 422, + 122, + 57, + 18, + -32, + -55 + ], + [ + 480, + 122, + 57, + 18, + -32, + -55 + ], + [ + 538, + 122, + 57, + 18, + -32, + -55 + ], + [ + 596, + 122, + 57, + 18, + -32, + -55 + ], + [ + 654, + 122, + 57, + 18, + -32, + -55 + ], + [ + 712, + 122, + 57, + 18, + -32, + -55 + ], + [ + 770, + 122, + 57, + 18, + -32, + -55 + ] + ], + [ + [ + 828, + 122, + 57, + 19, + -32, + -57 + ], + [ + 886, + 122, + 57, + 19, + -32, + -57 + ], + [ + 944, + 122, + 57, + 19, + -32, + -57 + ], + [ + 0, + 153, + 57, + 19, + -32, + -57 + ], + [ + 58, + 153, + 57, + 19, + -32, + -57 + ], + [ + 116, + 153, + 57, + 19, + -32, + -57 + ], + [ + 174, + 153, + 57, + 19, + -32, + -57 + ], + [ + 232, + 153, + 57, + 19, + -32, + -57 + ] + ], + [ + [ + 290, + 153, + 27, + 30, + -15, + -63 + ], + [ + 318, + 153, + 27, + 30, + -15, + -63 + ], + [ + 346, + 153, + 27, + 30, + -15, + -63 + ], + [ + 374, + 153, + 27, + 30, + -15, + -63 + ], + [ + 402, + 153, + 27, + 30, + -15, + -63 + ], + [ + 430, + 153, + 27, + 30, + -15, + -63 + ], + [ + 458, + 153, + 27, + 30, + -15, + -63 + ], + [ + 486, + 153, + 27, + 30, + -15, + -63 + ] + ], + [ + [ + 514, + 153, + 19, + 31, + -9, + -64 + ], + [ + 534, + 153, + 19, + 31, + -9, + -64 + ], + [ + 554, + 153, + 19, + 31, + -9, + -64 + ], + [ + 574, + 153, + 19, + 31, + -9, + -64 + ], + [ + 594, + 153, + 19, + 31, + -9, + -64 + ], + [ + 614, + 153, + 19, + 31, + -9, + -64 + ], + [ + 634, + 153, + 19, + 31, + -9, + -64 + ], + [ + 654, + 153, + 19, + 31, + -9, + -64 + ] + ], + [ + [ + 674, + 153, + 36, + 28, + -16, + -62 + ], + [ + 711, + 153, + 36, + 28, + -16, + -62 + ], + [ + 748, + 153, + 36, + 28, + -16, + -62 + ], + [ + 785, + 153, + 36, + 28, + -16, + -62 + ], + [ + 822, + 153, + 36, + 28, + -16, + -62 + ], + [ + 859, + 153, + 36, + 28, + -16, + -62 + ], + [ + 896, + 153, + 36, + 28, + -16, + -62 + ], + [ + 933, + 153, + 36, + 28, + -16, + -62 + ] + ], + [ + [ + 970, + 153, + 51, + 21, + -22, + -58 + ], + [ + 0, + 185, + 51, + 21, + -22, + -58 + ], + [ + 52, + 185, + 51, + 21, + -22, + -58 + ], + [ + 104, + 185, + 51, + 21, + -22, + -58 + ], + [ + 156, + 185, + 51, + 21, + -22, + -58 + ], + [ + 208, + 185, + 51, + 21, + -22, + -58 + ], + [ + 260, + 185, + 51, + 21, + -22, + -58 + ], + [ + 312, + 185, + 51, + 21, + -22, + -58 + ] + ], + [ + [ + 364, + 185, + 59, + 16, + -26, + -55 + ], + [ + 424, + 185, + 59, + 16, + -26, + -55 + ], + [ + 484, + 185, + 59, + 16, + -26, + -55 + ], + [ + 544, + 185, + 59, + 16, + -26, + -55 + ], + [ + 604, + 185, + 59, + 16, + -26, + -55 + ], + [ + 664, + 185, + 59, + 16, + -26, + -55 + ], + [ + 724, + 185, + 59, + 16, + -26, + -55 + ], + [ + 784, + 185, + 59, + 16, + -26, + -55 + ] + ], + [ + [ + 844, + 185, + 59, + 16, + -26, + -54 + ], + [ + 904, + 185, + 59, + 16, + -26, + -54 + ], + [ + 964, + 185, + 59, + 16, + -26, + -54 + ], + [ + 0, + 207, + 59, + 16, + -26, + -54 + ], + [ + 60, + 207, + 59, + 16, + -26, + -54 + ], + [ + 120, + 207, + 59, + 16, + -26, + -54 + ], + [ + 180, + 207, + 59, + 16, + -26, + -54 + ], + [ + 240, + 207, + 59, + 16, + -26, + -54 + ] + ], + [ + [ + 300, + 207, + 50, + 21, + -22, + -56 + ], + [ + 351, + 207, + 50, + 21, + -22, + -56 + ], + [ + 402, + 207, + 50, + 21, + -22, + -56 + ], + [ + 453, + 207, + 50, + 21, + -22, + -56 + ], + [ + 504, + 207, + 50, + 21, + -22, + -56 + ], + [ + 555, + 207, + 50, + 21, + -22, + -56 + ], + [ + 606, + 207, + 50, + 21, + -22, + -56 + ], + [ + 657, + 207, + 50, + 21, + -22, + -56 + ] + ], + [ + [ + 708, + 207, + 36, + 28, + -16, + -59 + ], + [ + 745, + 207, + 36, + 28, + -16, + -59 + ], + [ + 782, + 207, + 36, + 28, + -16, + -59 + ], + [ + 819, + 207, + 36, + 28, + -16, + -59 + ], + [ + 856, + 207, + 36, + 28, + -16, + -59 + ], + [ + 893, + 207, + 36, + 28, + -16, + -59 + ], + [ + 930, + 207, + 36, + 28, + -16, + -59 + ], + [ + 967, + 207, + 36, + 28, + -16, + -59 + ] + ], + [ + [ + 1004, + 207, + 19, + 31, + -9, + -60 + ], + [ + 0, + 239, + 19, + 31, + -9, + -60 + ], + [ + 20, + 239, + 19, + 31, + -9, + -60 + ], + [ + 40, + 239, + 19, + 31, + -9, + -60 + ], + [ + 60, + 239, + 19, + 31, + -9, + -60 + ], + [ + 80, + 239, + 19, + 31, + -9, + -60 + ], + [ + 100, + 239, + 19, + 31, + -9, + -60 + ], + [ + 120, + 239, + 19, + 31, + -9, + -60 + ] + ], + [ + [ + 140, + 239, + 19, + 31, + -10, + -60 + ], + [ + 160, + 239, + 19, + 31, + -10, + -60 + ], + [ + 180, + 239, + 19, + 31, + -10, + -60 + ], + [ + 200, + 239, + 19, + 31, + -10, + -60 + ], + [ + 220, + 239, + 19, + 31, + -10, + -60 + ], + [ + 240, + 239, + 19, + 31, + -10, + -60 + ], + [ + 260, + 239, + 19, + 31, + -10, + -60 + ], + [ + 280, + 239, + 19, + 31, + -10, + -60 + ] + ], + [ + [ + 300, + 239, + 36, + 28, + -20, + -59 + ], + [ + 337, + 239, + 36, + 28, + -20, + -59 + ], + [ + 374, + 239, + 36, + 28, + -20, + -59 + ], + [ + 411, + 239, + 36, + 28, + -20, + -59 + ], + [ + 448, + 239, + 36, + 28, + -20, + -59 + ], + [ + 485, + 239, + 36, + 28, + -20, + -59 + ], + [ + 522, + 239, + 36, + 28, + -20, + -59 + ], + [ + 559, + 239, + 36, + 28, + -20, + -59 + ] + ], + [ + [ + 596, + 239, + 52, + 21, + -29, + -56 + ], + [ + 649, + 239, + 52, + 21, + -29, + -56 + ], + [ + 702, + 239, + 52, + 21, + -29, + -56 + ], + [ + 755, + 239, + 52, + 21, + -29, + -56 + ], + [ + 808, + 239, + 52, + 21, + -29, + -56 + ], + [ + 861, + 239, + 52, + 21, + -29, + -56 + ], + [ + 914, + 239, + 52, + 21, + -29, + -56 + ], + [ + 967, + 239, + 52, + 21, + -29, + -56 + ] + ], + [ + [ + 0, + 271, + 59, + 16, + -33, + -54 + ], + [ + 60, + 271, + 59, + 16, + -33, + -54 + ], + [ + 120, + 271, + 59, + 16, + -33, + -54 + ], + [ + 180, + 271, + 59, + 16, + -33, + -54 + ], + [ + 240, + 271, + 59, + 16, + -33, + -54 + ], + [ + 300, + 271, + 59, + 16, + -33, + -54 + ], + [ + 360, + 271, + 59, + 16, + -33, + -54 + ], + [ + 420, + 271, + 59, + 16, + -33, + -54 + ] + ], + [ + [ + 480, + 271, + 59, + 16, + -33, + -55 + ], + [ + 540, + 271, + 59, + 16, + -33, + -55 + ], + [ + 600, + 271, + 59, + 16, + -33, + -55 + ], + [ + 660, + 271, + 59, + 16, + -33, + -55 + ], + [ + 720, + 271, + 59, + 16, + -33, + -55 + ], + [ + 780, + 271, + 59, + 16, + -33, + -55 + ], + [ + 840, + 271, + 59, + 16, + -33, + -55 + ], + [ + 900, + 271, + 59, + 16, + -33, + -55 + ] + ], + [ + [ + 960, + 271, + 52, + 21, + -29, + -58 + ], + [ + 0, + 293, + 52, + 21, + -29, + -58 + ], + [ + 53, + 293, + 52, + 21, + -29, + -58 + ], + [ + 106, + 293, + 52, + 21, + -29, + -58 + ], + [ + 159, + 293, + 52, + 21, + -29, + -58 + ], + [ + 212, + 293, + 52, + 21, + -29, + -58 + ], + [ + 265, + 293, + 52, + 21, + -29, + -58 + ], + [ + 318, + 293, + 52, + 21, + -29, + -58 + ] + ], + [ + [ + 371, + 293, + 36, + 28, + -20, + -62 + ], + [ + 408, + 293, + 36, + 28, + -20, + -62 + ], + [ + 445, + 293, + 36, + 28, + -20, + -62 + ], + [ + 482, + 293, + 36, + 28, + -20, + -62 + ], + [ + 519, + 293, + 36, + 28, + -20, + -62 + ], + [ + 556, + 293, + 36, + 28, + -20, + -62 + ], + [ + 593, + 293, + 36, + 28, + -20, + -62 + ], + [ + 630, + 293, + 36, + 28, + -20, + -62 + ] + ], + [ + [ + 667, + 293, + 19, + 31, + -10, + -64 + ], + [ + 687, + 293, + 19, + 31, + -10, + -64 + ], + [ + 707, + 293, + 19, + 31, + -10, + -64 + ], + [ + 727, + 293, + 19, + 31, + -10, + -64 + ], + [ + 747, + 293, + 19, + 31, + -10, + -64 + ], + [ + 767, + 293, + 19, + 31, + -10, + -64 + ], + [ + 787, + 293, + 19, + 31, + -10, + -64 + ], + [ + 807, + 293, + 19, + 31, + -10, + -64 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/icearrow.png b/public/missiles/icearrow.png new file mode 100644 index 0000000..0e2c020 Binary files /dev/null and b/public/missiles/icearrow.png differ diff --git a/public/missiles/iceblast.json b/public/missiles/iceblast.json new file mode 100644 index 0000000..53ac494 --- /dev/null +++ b/public/missiles/iceblast.json @@ -0,0 +1,683 @@ +{ + "name": "iceblast", + "celFile": "IceBlast", + "width": 1024, + "height": 431, + "directions": 16, + "framesPerDirection": 5, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 74, + 54, + -16, + -71 + ], + [ + 75, + 0, + 74, + 54, + -16, + -71 + ], + [ + 150, + 0, + 74, + 54, + -16, + -71 + ], + [ + 225, + 0, + 74, + 54, + -16, + -71 + ], + [ + 300, + 0, + 74, + 54, + -16, + -71 + ] + ], + [ + [ + 375, + 0, + 85, + 56, + -14, + -51 + ], + [ + 461, + 0, + 85, + 56, + -14, + -51 + ], + [ + 547, + 0, + 85, + 56, + -14, + -51 + ], + [ + 633, + 0, + 85, + 56, + -14, + -51 + ], + [ + 719, + 0, + 85, + 56, + -14, + -51 + ] + ], + [ + [ + 805, + 0, + 86, + 51, + -70, + -51 + ], + [ + 892, + 0, + 86, + 51, + -70, + -51 + ], + [ + 0, + 57, + 86, + 51, + -70, + -51 + ], + [ + 87, + 57, + 86, + 51, + -70, + -51 + ], + [ + 174, + 57, + 86, + 51, + -70, + -51 + ] + ], + [ + [ + 261, + 57, + 72, + 54, + -58, + -72 + ], + [ + 334, + 57, + 72, + 54, + -58, + -72 + ], + [ + 407, + 57, + 72, + 54, + -58, + -72 + ], + [ + 480, + 57, + 72, + 54, + -58, + -72 + ], + [ + 553, + 57, + 72, + 54, + -58, + -72 + ] + ], + [ + [ + 626, + 57, + 45, + 59, + -23, + -78 + ], + [ + 672, + 57, + 45, + 59, + -23, + -78 + ], + [ + 718, + 57, + 45, + 59, + -23, + -78 + ], + [ + 764, + 57, + 45, + 59, + -23, + -78 + ], + [ + 810, + 57, + 45, + 59, + -23, + -78 + ] + ], + [ + [ + 856, + 57, + 100, + 41, + -16, + -54 + ], + [ + 0, + 117, + 100, + 41, + -16, + -54 + ], + [ + 101, + 117, + 100, + 41, + -16, + -54 + ], + [ + 202, + 117, + 100, + 41, + -16, + -54 + ], + [ + 303, + 117, + 100, + 41, + -16, + -54 + ] + ], + [ + [ + 404, + 117, + 51, + 67, + -26, + -51 + ], + [ + 456, + 117, + 51, + 67, + -26, + -51 + ], + [ + 508, + 117, + 51, + 67, + -26, + -51 + ], + [ + 560, + 117, + 51, + 67, + -26, + -51 + ], + [ + 612, + 117, + 51, + 67, + -26, + -51 + ] + ], + [ + [ + 664, + 117, + 101, + 45, + -85, + -55 + ], + [ + 766, + 117, + 101, + 45, + -85, + -55 + ], + [ + 868, + 117, + 101, + 45, + -85, + -55 + ], + [ + 0, + 185, + 101, + 45, + -85, + -55 + ], + [ + 102, + 185, + 101, + 45, + -85, + -55 + ] + ], + [ + [ + 204, + 185, + 53, + 57, + -17, + -76 + ], + [ + 258, + 185, + 53, + 57, + -17, + -76 + ], + [ + 312, + 185, + 53, + 57, + -17, + -76 + ], + [ + 366, + 185, + 53, + 57, + -17, + -76 + ], + [ + 420, + 185, + 53, + 57, + -17, + -76 + ] + ], + [ + [ + 474, + 185, + 91, + 48, + -16, + -63 + ], + [ + 566, + 185, + 91, + 48, + -16, + -63 + ], + [ + 658, + 185, + 91, + 48, + -16, + -63 + ], + [ + 750, + 185, + 91, + 48, + -16, + -63 + ], + [ + 842, + 185, + 91, + 48, + -16, + -63 + ] + ], + [ + [ + 0, + 243, + 99, + 42, + -15, + -50 + ], + [ + 100, + 243, + 99, + 42, + -15, + -50 + ], + [ + 200, + 243, + 99, + 42, + -15, + -50 + ], + [ + 300, + 243, + 99, + 42, + -15, + -50 + ], + [ + 400, + 243, + 99, + 42, + -15, + -50 + ] + ], + [ + [ + 500, + 243, + 63, + 65, + -15, + -51 + ], + [ + 564, + 243, + 63, + 65, + -15, + -51 + ], + [ + 628, + 243, + 63, + 65, + -15, + -51 + ], + [ + 692, + 243, + 63, + 65, + -15, + -51 + ], + [ + 756, + 243, + 63, + 65, + -15, + -51 + ] + ], + [ + [ + 820, + 243, + 64, + 62, + -47, + -51 + ], + [ + 885, + 243, + 64, + 62, + -47, + -51 + ], + [ + 950, + 243, + 64, + 62, + -47, + -51 + ], + [ + 0, + 309, + 64, + 62, + -47, + -51 + ], + [ + 65, + 309, + 64, + 62, + -47, + -51 + ] + ], + [ + [ + 130, + 309, + 99, + 45, + -83, + -50 + ], + [ + 230, + 309, + 99, + 45, + -83, + -50 + ], + [ + 330, + 309, + 99, + 45, + -83, + -50 + ], + [ + 430, + 309, + 99, + 45, + -83, + -50 + ], + [ + 530, + 309, + 99, + 45, + -83, + -50 + ] + ], + [ + [ + 630, + 309, + 90, + 49, + -75, + -65 + ], + [ + 721, + 309, + 90, + 49, + -75, + -65 + ], + [ + 812, + 309, + 90, + 49, + -75, + -65 + ], + [ + 903, + 309, + 90, + 49, + -75, + -65 + ], + [ + 0, + 372, + 90, + 49, + -75, + -65 + ] + ], + [ + [ + 91, + 372, + 52, + 59, + -38, + -77 + ], + [ + 144, + 372, + 52, + 59, + -38, + -77 + ], + [ + 197, + 372, + 52, + 59, + -38, + -77 + ], + [ + 250, + 372, + 52, + 59, + -38, + -77 + ], + [ + 303, + 372, + 52, + 59, + -38, + -77 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/iceblast.png b/public/missiles/iceblast.png new file mode 100644 index 0000000..5e1136b Binary files /dev/null and b/public/missiles/iceblast.png differ diff --git a/public/missiles/icebolt.json b/public/missiles/icebolt.json new file mode 100644 index 0000000..c059af3 --- /dev/null +++ b/public/missiles/icebolt.json @@ -0,0 +1,811 @@ +{ + "name": "icebolt", + "celFile": "Icebolt", + "width": 512, + "height": 357, + "directions": 16, + "framesPerDirection": 6, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 51, + 27, + -18, + -65 + ], + [ + 52, + 0, + 51, + 27, + -18, + -65 + ], + [ + 104, + 0, + 51, + 27, + -18, + -65 + ], + [ + 156, + 0, + 51, + 27, + -18, + -65 + ], + [ + 208, + 0, + 51, + 27, + -18, + -65 + ], + [ + 260, + 0, + 51, + 27, + -18, + -65 + ] + ], + [ + [ + 312, + 0, + 55, + 28, + -17, + -53 + ], + [ + 368, + 0, + 55, + 28, + -17, + -53 + ], + [ + 424, + 0, + 55, + 28, + -17, + -53 + ], + [ + 0, + 29, + 55, + 28, + -17, + -53 + ], + [ + 56, + 29, + 55, + 28, + -17, + -53 + ], + [ + 112, + 29, + 55, + 28, + -17, + -53 + ] + ], + [ + [ + 168, + 29, + 54, + 34, + -37, + -53 + ], + [ + 223, + 29, + 54, + 34, + -37, + -53 + ], + [ + 278, + 29, + 54, + 34, + -37, + -53 + ], + [ + 333, + 29, + 54, + 34, + -37, + -53 + ], + [ + 388, + 29, + 54, + 34, + -37, + -53 + ], + [ + 443, + 29, + 54, + 34, + -37, + -53 + ] + ], + [ + [ + 0, + 64, + 53, + 29, + -35, + -67 + ], + [ + 54, + 64, + 53, + 29, + -35, + -67 + ], + [ + 108, + 64, + 53, + 29, + -35, + -67 + ], + [ + 162, + 64, + 53, + 29, + -35, + -67 + ], + [ + 216, + 64, + 53, + 29, + -35, + -67 + ], + [ + 270, + 64, + 53, + 29, + -35, + -67 + ] + ], + [ + [ + 324, + 64, + 16, + 37, + -8, + -71 + ], + [ + 341, + 64, + 16, + 37, + -8, + -71 + ], + [ + 358, + 64, + 16, + 37, + -8, + -71 + ], + [ + 375, + 64, + 16, + 37, + -8, + -71 + ], + [ + 392, + 64, + 16, + 37, + -8, + -71 + ], + [ + 409, + 64, + 16, + 37, + -8, + -71 + ] + ], + [ + [ + 426, + 64, + 70, + 21, + -24, + -58 + ], + [ + 0, + 102, + 70, + 21, + -24, + -58 + ], + [ + 71, + 102, + 70, + 21, + -24, + -58 + ], + [ + 142, + 102, + 70, + 21, + -24, + -58 + ], + [ + 213, + 102, + 70, + 21, + -24, + -58 + ], + [ + 284, + 102, + 70, + 21, + -24, + -58 + ] + ], + [ + [ + 355, + 102, + 18, + 39, + -9, + -55 + ], + [ + 374, + 102, + 18, + 39, + -9, + -55 + ], + [ + 393, + 102, + 18, + 39, + -9, + -55 + ], + [ + 412, + 102, + 18, + 39, + -9, + -55 + ], + [ + 431, + 102, + 18, + 39, + -9, + -55 + ], + [ + 450, + 102, + 18, + 39, + -9, + -55 + ] + ], + [ + [ + 0, + 142, + 70, + 25, + -46, + -57 + ], + [ + 71, + 142, + 70, + 25, + -46, + -57 + ], + [ + 142, + 142, + 70, + 25, + -46, + -57 + ], + [ + 213, + 142, + 70, + 25, + -46, + -57 + ], + [ + 284, + 142, + 70, + 25, + -46, + -57 + ], + [ + 355, + 142, + 70, + 25, + -46, + -57 + ] + ], + [ + [ + 426, + 142, + 29, + 36, + -10, + -71 + ], + [ + 456, + 142, + 29, + 36, + -10, + -71 + ], + [ + 0, + 179, + 29, + 36, + -10, + -71 + ], + [ + 30, + 179, + 29, + 36, + -10, + -71 + ], + [ + 60, + 179, + 29, + 36, + -10, + -71 + ], + [ + 90, + 179, + 29, + 36, + -10, + -71 + ] + ], + [ + [ + 120, + 179, + 66, + 24, + -23, + -64 + ], + [ + 187, + 179, + 66, + 24, + -23, + -64 + ], + [ + 254, + 179, + 66, + 24, + -23, + -64 + ], + [ + 321, + 179, + 66, + 24, + -23, + -64 + ], + [ + 388, + 179, + 66, + 24, + -23, + -64 + ], + [ + 0, + 216, + 66, + 24, + -23, + -64 + ] + ], + [ + [ + 67, + 216, + 66, + 20, + -22, + -51 + ], + [ + 134, + 216, + 66, + 20, + -22, + -51 + ], + [ + 201, + 216, + 66, + 20, + -22, + -51 + ], + [ + 268, + 216, + 66, + 20, + -22, + -51 + ], + [ + 335, + 216, + 66, + 20, + -22, + -51 + ], + [ + 402, + 216, + 66, + 20, + -22, + -51 + ] + ], + [ + [ + 469, + 216, + 35, + 36, + -9, + -55 + ], + [ + 0, + 253, + 35, + 36, + -9, + -55 + ], + [ + 36, + 253, + 35, + 36, + -9, + -55 + ], + [ + 72, + 253, + 35, + 36, + -9, + -55 + ], + [ + 108, + 253, + 35, + 36, + -9, + -55 + ], + [ + 144, + 253, + 35, + 36, + -9, + -55 + ] + ], + [ + [ + 180, + 253, + 31, + 39, + -22, + -55 + ], + [ + 212, + 253, + 31, + 39, + -22, + -55 + ], + [ + 244, + 253, + 31, + 39, + -22, + -55 + ], + [ + 276, + 253, + 31, + 39, + -22, + -55 + ], + [ + 308, + 253, + 31, + 39, + -22, + -55 + ], + [ + 340, + 253, + 31, + 39, + -22, + -55 + ] + ], + [ + [ + 372, + 253, + 67, + 27, + -45, + -52 + ], + [ + 440, + 253, + 67, + 27, + -45, + -52 + ], + [ + 0, + 293, + 67, + 27, + -45, + -52 + ], + [ + 68, + 293, + 67, + 27, + -45, + -52 + ], + [ + 136, + 293, + 67, + 27, + -45, + -52 + ], + [ + 204, + 293, + 67, + 27, + -45, + -52 + ] + ], + [ + [ + 272, + 293, + 66, + 23, + -43, + -62 + ], + [ + 339, + 293, + 66, + 23, + -43, + -62 + ], + [ + 406, + 293, + 66, + 23, + -43, + -62 + ], + [ + 0, + 321, + 66, + 23, + -43, + -62 + ], + [ + 67, + 321, + 66, + 23, + -43, + -62 + ], + [ + 134, + 321, + 66, + 23, + -43, + -62 + ] + ], + [ + [ + 201, + 321, + 33, + 36, + -23, + -71 + ], + [ + 235, + 321, + 33, + 36, + -23, + -71 + ], + [ + 269, + 321, + 33, + 36, + -23, + -71 + ], + [ + 303, + 321, + 33, + 36, + -23, + -71 + ], + [ + 337, + 321, + 33, + 36, + -23, + -71 + ], + [ + 371, + 321, + 33, + 36, + -23, + -71 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/icebolt.png b/public/missiles/icebolt.png new file mode 100644 index 0000000..6030193 Binary files /dev/null and b/public/missiles/icebolt.png differ diff --git a/public/missiles/iceexplode.json b/public/missiles/iceexplode.json new file mode 100644 index 0000000..4efd403 --- /dev/null +++ b/public/missiles/iceexplode.json @@ -0,0 +1,141 @@ +{ + "name": "iceexplode", + "celFile": "IceArrowExplode", + "width": 512, + "height": 332, + "directions": 1, + "framesPerDirection": 16, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 83, + 110, + -43, + -90 + ], + [ + 84, + 0, + 83, + 110, + -43, + -90 + ], + [ + 168, + 0, + 83, + 110, + -43, + -90 + ], + [ + 252, + 0, + 83, + 110, + -43, + -90 + ], + [ + 336, + 0, + 83, + 110, + -43, + -90 + ], + [ + 420, + 0, + 83, + 110, + -43, + -90 + ], + [ + 0, + 111, + 83, + 110, + -43, + -90 + ], + [ + 84, + 111, + 83, + 110, + -43, + -90 + ], + [ + 168, + 111, + 83, + 110, + -43, + -90 + ], + [ + 252, + 111, + 83, + 110, + -43, + -90 + ], + [ + 336, + 111, + 83, + 110, + -43, + -90 + ], + [ + 420, + 111, + 83, + 110, + -43, + -90 + ], + [ + 0, + 222, + 83, + 110, + -43, + -90 + ], + [ + 84, + 222, + 83, + 110, + -43, + -90 + ], + [ + 168, + 222, + 83, + 110, + -43, + -90 + ], + [ + 252, + 222, + 83, + 110, + -43, + -90 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/iceexplode.png b/public/missiles/iceexplode.png new file mode 100644 index 0000000..4f7745e Binary files /dev/null and b/public/missiles/iceexplode.png differ diff --git a/public/missiles/lightningjavelin.json b/public/missiles/lightningjavelin.json new file mode 100644 index 0000000..f2a190f --- /dev/null +++ b/public/missiles/lightningjavelin.json @@ -0,0 +1,683 @@ +{ + "name": "lightningjavelin", + "celFile": "LightningJavelin", + "width": 1024, + "height": 642, + "directions": 16, + "framesPerDirection": 5, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 100, + 63, + -42, + -83 + ], + [ + 101, + 0, + 100, + 63, + -42, + -83 + ], + [ + 202, + 0, + 100, + 63, + -42, + -83 + ], + [ + 303, + 0, + 100, + 63, + -42, + -83 + ], + [ + 404, + 0, + 100, + 63, + -42, + -83 + ] + ], + [ + [ + 505, + 0, + 111, + 67, + -39, + -89 + ], + [ + 617, + 0, + 111, + 67, + -39, + -89 + ], + [ + 729, + 0, + 111, + 67, + -39, + -89 + ], + [ + 841, + 0, + 111, + 67, + -39, + -89 + ], + [ + 0, + 68, + 111, + 67, + -39, + -89 + ] + ], + [ + [ + 112, + 68, + 108, + 67, + -68, + -89 + ], + [ + 221, + 68, + 108, + 67, + -68, + -89 + ], + [ + 330, + 68, + 108, + 67, + -68, + -89 + ], + [ + 439, + 68, + 108, + 67, + -68, + -89 + ], + [ + 548, + 68, + 108, + 67, + -68, + -89 + ] + ], + [ + [ + 657, + 68, + 101, + 62, + -60, + -82 + ], + [ + 759, + 68, + 101, + 62, + -60, + -82 + ], + [ + 861, + 68, + 101, + 62, + -60, + -82 + ], + [ + 0, + 136, + 101, + 62, + -60, + -82 + ], + [ + 102, + 136, + 101, + 62, + -60, + -82 + ] + ], + [ + [ + 204, + 136, + 60, + 71, + -31, + -89 + ], + [ + 265, + 136, + 60, + 71, + -31, + -89 + ], + [ + 326, + 136, + 60, + 71, + -31, + -89 + ], + [ + 387, + 136, + 60, + 71, + -31, + -89 + ], + [ + 448, + 136, + 60, + 71, + -31, + -89 + ] + ], + [ + [ + 509, + 136, + 133, + 60, + -45, + -86 + ], + [ + 643, + 136, + 133, + 60, + -45, + -86 + ], + [ + 777, + 136, + 133, + 60, + -45, + -86 + ], + [ + 0, + 208, + 133, + 60, + -45, + -86 + ], + [ + 134, + 208, + 133, + 60, + -45, + -86 + ] + ], + [ + [ + 268, + 208, + 56, + 79, + -27, + -90 + ], + [ + 325, + 208, + 56, + 79, + -27, + -90 + ], + [ + 382, + 208, + 56, + 79, + -27, + -90 + ], + [ + 439, + 208, + 56, + 79, + -27, + -90 + ], + [ + 496, + 208, + 56, + 79, + -27, + -90 + ] + ], + [ + [ + 553, + 208, + 131, + 60, + -86, + -85 + ], + [ + 685, + 208, + 131, + 60, + -86, + -85 + ], + [ + 817, + 208, + 131, + 60, + -86, + -85 + ], + [ + 0, + 288, + 131, + 60, + -86, + -85 + ], + [ + 132, + 288, + 131, + 60, + -86, + -85 + ] + ], + [ + [ + 264, + 288, + 71, + 69, + -37, + -88 + ], + [ + 336, + 288, + 71, + 69, + -37, + -88 + ], + [ + 408, + 288, + 71, + 69, + -37, + -88 + ], + [ + 480, + 288, + 71, + 69, + -37, + -88 + ], + [ + 552, + 288, + 71, + 69, + -37, + -88 + ] + ], + [ + [ + 624, + 288, + 123, + 61, + -45, + -84 + ], + [ + 748, + 288, + 123, + 61, + -45, + -84 + ], + [ + 872, + 288, + 123, + 61, + -45, + -84 + ], + [ + 0, + 358, + 123, + 61, + -45, + -84 + ], + [ + 124, + 358, + 123, + 61, + -45, + -84 + ] + ], + [ + [ + 248, + 358, + 129, + 60, + -43, + -88 + ], + [ + 378, + 358, + 129, + 60, + -43, + -88 + ], + [ + 508, + 358, + 129, + 60, + -43, + -88 + ], + [ + 638, + 358, + 129, + 60, + -43, + -88 + ], + [ + 768, + 358, + 129, + 60, + -43, + -88 + ] + ], + [ + [ + 898, + 358, + 78, + 76, + -33, + -90 + ], + [ + 0, + 435, + 78, + 76, + -33, + -90 + ], + [ + 79, + 435, + 78, + 76, + -33, + -90 + ], + [ + 158, + 435, + 78, + 76, + -33, + -90 + ], + [ + 237, + 435, + 78, + 76, + -33, + -90 + ] + ], + [ + [ + 316, + 435, + 76, + 76, + -41, + -90 + ], + [ + 393, + 435, + 76, + 76, + -41, + -90 + ], + [ + 470, + 435, + 76, + 76, + -41, + -90 + ], + [ + 547, + 435, + 76, + 76, + -41, + -90 + ], + [ + 624, + 435, + 76, + 76, + -41, + -90 + ] + ], + [ + [ + 701, + 435, + 127, + 59, + -84, + -87 + ], + [ + 829, + 435, + 127, + 59, + -84, + -87 + ], + [ + 0, + 512, + 127, + 59, + -84, + -87 + ], + [ + 128, + 512, + 127, + 59, + -84, + -87 + ], + [ + 256, + 512, + 127, + 59, + -84, + -87 + ] + ], + [ + [ + 384, + 512, + 121, + 61, + -77, + -83 + ], + [ + 506, + 512, + 121, + 61, + -77, + -83 + ], + [ + 628, + 512, + 121, + 61, + -77, + -83 + ], + [ + 750, + 512, + 121, + 61, + -77, + -83 + ], + [ + 872, + 512, + 121, + 61, + -77, + -83 + ] + ], + [ + [ + 0, + 574, + 71, + 68, + -36, + -86 + ], + [ + 72, + 574, + 71, + 68, + -36, + -86 + ], + [ + 144, + 574, + 71, + 68, + -36, + -86 + ], + [ + 216, + 574, + 71, + 68, + -36, + -86 + ], + [ + 288, + 574, + 71, + 68, + -36, + -86 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/lightningjavelin.png b/public/missiles/lightningjavelin.png new file mode 100644 index 0000000..8714af9 Binary files /dev/null and b/public/missiles/lightningjavelin.png differ diff --git a/public/missiles/magicarrow.json b/public/missiles/magicarrow.json new file mode 100644 index 0000000..2ad32dd --- /dev/null +++ b/public/missiles/magicarrow.json @@ -0,0 +1,2123 @@ +{ + "name": "magicarrow", + "celFile": "SafeArrow", + "width": 1024, + "height": 287, + "directions": 32, + "framesPerDirection": 8, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 41, + 24, + -18, + -60 + ], + [ + 42, + 0, + 41, + 24, + -18, + -60 + ], + [ + 84, + 0, + 41, + 24, + -18, + -60 + ], + [ + 126, + 0, + 41, + 24, + -18, + -60 + ], + [ + 168, + 0, + 41, + 24, + -18, + -60 + ], + [ + 210, + 0, + 41, + 24, + -18, + -60 + ], + [ + 252, + 0, + 41, + 24, + -18, + -60 + ], + [ + 294, + 0, + 41, + 24, + -18, + -60 + ] + ], + [ + [ + 336, + 0, + 40, + 25, + -18, + -58 + ], + [ + 377, + 0, + 40, + 25, + -18, + -58 + ], + [ + 418, + 0, + 40, + 25, + -18, + -58 + ], + [ + 459, + 0, + 40, + 25, + -18, + -58 + ], + [ + 500, + 0, + 40, + 25, + -18, + -58 + ], + [ + 541, + 0, + 40, + 25, + -18, + -58 + ], + [ + 582, + 0, + 40, + 25, + -18, + -58 + ], + [ + 623, + 0, + 40, + 25, + -18, + -58 + ] + ], + [ + [ + 664, + 0, + 40, + 25, + -22, + -58 + ], + [ + 705, + 0, + 40, + 25, + -22, + -58 + ], + [ + 746, + 0, + 40, + 25, + -22, + -58 + ], + [ + 787, + 0, + 40, + 25, + -22, + -58 + ], + [ + 828, + 0, + 40, + 25, + -22, + -58 + ], + [ + 869, + 0, + 40, + 25, + -22, + -58 + ], + [ + 910, + 0, + 40, + 25, + -22, + -58 + ], + [ + 951, + 0, + 40, + 25, + -22, + -58 + ] + ], + [ + [ + 0, + 26, + 41, + 24, + -23, + -60 + ], + [ + 42, + 26, + 41, + 24, + -23, + -60 + ], + [ + 84, + 26, + 41, + 24, + -23, + -60 + ], + [ + 126, + 26, + 41, + 24, + -23, + -60 + ], + [ + 168, + 26, + 41, + 24, + -23, + -60 + ], + [ + 210, + 26, + 41, + 24, + -23, + -60 + ], + [ + 252, + 26, + 41, + 24, + -23, + -60 + ], + [ + 294, + 26, + 41, + 24, + -23, + -60 + ] + ], + [ + [ + 336, + 26, + 18, + 31, + -9, + -64 + ], + [ + 355, + 26, + 18, + 31, + -9, + -64 + ], + [ + 374, + 26, + 18, + 31, + -9, + -64 + ], + [ + 393, + 26, + 18, + 31, + -9, + -64 + ], + [ + 412, + 26, + 18, + 31, + -9, + -64 + ], + [ + 431, + 26, + 18, + 31, + -9, + -64 + ], + [ + 450, + 26, + 18, + 31, + -9, + -64 + ], + [ + 469, + 26, + 18, + 31, + -9, + -64 + ] + ], + [ + [ + 488, + 26, + 53, + 17, + -23, + -55 + ], + [ + 542, + 26, + 53, + 17, + -23, + -55 + ], + [ + 596, + 26, + 53, + 17, + -23, + -55 + ], + [ + 650, + 26, + 53, + 17, + -23, + -55 + ], + [ + 704, + 26, + 53, + 17, + -23, + -55 + ], + [ + 758, + 26, + 53, + 17, + -23, + -55 + ], + [ + 812, + 26, + 53, + 17, + -23, + -55 + ], + [ + 866, + 26, + 53, + 17, + -23, + -55 + ] + ], + [ + [ + 920, + 26, + 18, + 30, + -9, + -60 + ], + [ + 939, + 26, + 18, + 30, + -9, + -60 + ], + [ + 958, + 26, + 18, + 30, + -9, + -60 + ], + [ + 977, + 26, + 18, + 30, + -9, + -60 + ], + [ + 996, + 26, + 18, + 30, + -9, + -60 + ], + [ + 0, + 58, + 18, + 30, + -9, + -60 + ], + [ + 19, + 58, + 18, + 30, + -9, + -60 + ], + [ + 38, + 58, + 18, + 30, + -9, + -60 + ] + ], + [ + [ + 57, + 58, + 51, + 17, + -29, + -55 + ], + [ + 109, + 58, + 51, + 17, + -29, + -55 + ], + [ + 161, + 58, + 51, + 17, + -29, + -55 + ], + [ + 213, + 58, + 51, + 17, + -29, + -55 + ], + [ + 265, + 58, + 51, + 17, + -29, + -55 + ], + [ + 317, + 58, + 51, + 17, + -29, + -55 + ], + [ + 369, + 58, + 51, + 17, + -29, + -55 + ], + [ + 421, + 58, + 51, + 17, + -29, + -55 + ] + ], + [ + [ + 473, + 58, + 26, + 28, + -12, + -62 + ], + [ + 500, + 58, + 26, + 28, + -12, + -62 + ], + [ + 527, + 58, + 26, + 28, + -12, + -62 + ], + [ + 554, + 58, + 26, + 28, + -12, + -62 + ], + [ + 581, + 58, + 26, + 28, + -12, + -62 + ], + [ + 608, + 58, + 26, + 28, + -12, + -62 + ], + [ + 635, + 58, + 26, + 28, + -12, + -62 + ], + [ + 662, + 58, + 26, + 28, + -12, + -62 + ] + ], + [ + [ + 689, + 58, + 50, + 19, + -22, + -57 + ], + [ + 740, + 58, + 50, + 19, + -22, + -57 + ], + [ + 791, + 58, + 50, + 19, + -22, + -57 + ], + [ + 842, + 58, + 50, + 19, + -22, + -57 + ], + [ + 893, + 58, + 50, + 19, + -22, + -57 + ], + [ + 944, + 58, + 50, + 19, + -22, + -57 + ], + [ + 0, + 89, + 50, + 19, + -22, + -57 + ], + [ + 51, + 89, + 50, + 19, + -22, + -57 + ] + ], + [ + [ + 102, + 89, + 48, + 20, + -21, + -56 + ], + [ + 151, + 89, + 48, + 20, + -21, + -56 + ], + [ + 200, + 89, + 48, + 20, + -21, + -56 + ], + [ + 249, + 89, + 48, + 20, + -21, + -56 + ], + [ + 298, + 89, + 48, + 20, + -21, + -56 + ], + [ + 347, + 89, + 48, + 20, + -21, + -56 + ], + [ + 396, + 89, + 48, + 20, + -21, + -56 + ], + [ + 445, + 89, + 48, + 20, + -21, + -56 + ] + ], + [ + [ + 494, + 89, + 27, + 28, + -12, + -59 + ], + [ + 522, + 89, + 27, + 28, + -12, + -59 + ], + [ + 550, + 89, + 27, + 28, + -12, + -59 + ], + [ + 578, + 89, + 27, + 28, + -12, + -59 + ], + [ + 606, + 89, + 27, + 28, + -12, + -59 + ], + [ + 634, + 89, + 27, + 28, + -12, + -59 + ], + [ + 662, + 89, + 27, + 28, + -12, + -59 + ], + [ + 690, + 89, + 27, + 28, + -12, + -59 + ] + ], + [ + [ + 718, + 89, + 27, + 28, + -15, + -59 + ], + [ + 746, + 89, + 27, + 28, + -15, + -59 + ], + [ + 774, + 89, + 27, + 28, + -15, + -59 + ], + [ + 802, + 89, + 27, + 28, + -15, + -59 + ], + [ + 830, + 89, + 27, + 28, + -15, + -59 + ], + [ + 858, + 89, + 27, + 28, + -15, + -59 + ], + [ + 886, + 89, + 27, + 28, + -15, + -59 + ], + [ + 914, + 89, + 27, + 28, + -15, + -59 + ] + ], + [ + [ + 942, + 89, + 50, + 20, + -28, + -56 + ], + [ + 0, + 118, + 50, + 20, + -28, + -56 + ], + [ + 51, + 118, + 50, + 20, + -28, + -56 + ], + [ + 102, + 118, + 50, + 20, + -28, + -56 + ], + [ + 153, + 118, + 50, + 20, + -28, + -56 + ], + [ + 204, + 118, + 50, + 20, + -28, + -56 + ], + [ + 255, + 118, + 50, + 20, + -28, + -56 + ], + [ + 306, + 118, + 50, + 20, + -28, + -56 + ] + ], + [ + [ + 357, + 118, + 50, + 19, + -28, + -57 + ], + [ + 408, + 118, + 50, + 19, + -28, + -57 + ], + [ + 459, + 118, + 50, + 19, + -28, + -57 + ], + [ + 510, + 118, + 50, + 19, + -28, + -57 + ], + [ + 561, + 118, + 50, + 19, + -28, + -57 + ], + [ + 612, + 118, + 50, + 19, + -28, + -57 + ], + [ + 663, + 118, + 50, + 19, + -28, + -57 + ], + [ + 714, + 118, + 50, + 19, + -28, + -57 + ] + ], + [ + [ + 765, + 118, + 27, + 28, + -15, + -62 + ], + [ + 793, + 118, + 27, + 28, + -15, + -62 + ], + [ + 821, + 118, + 27, + 28, + -15, + -62 + ], + [ + 849, + 118, + 27, + 28, + -15, + -62 + ], + [ + 877, + 118, + 27, + 28, + -15, + -62 + ], + [ + 905, + 118, + 27, + 28, + -15, + -62 + ], + [ + 933, + 118, + 27, + 28, + -15, + -62 + ], + [ + 961, + 118, + 27, + 28, + -15, + -62 + ] + ], + [ + [ + 989, + 118, + 20, + 30, + -9, + -63 + ], + [ + 0, + 149, + 20, + 30, + -9, + -63 + ], + [ + 21, + 149, + 20, + 30, + -9, + -63 + ], + [ + 42, + 149, + 20, + 30, + -9, + -63 + ], + [ + 63, + 149, + 20, + 30, + -9, + -63 + ], + [ + 84, + 149, + 20, + 30, + -9, + -63 + ], + [ + 105, + 149, + 20, + 30, + -9, + -63 + ], + [ + 126, + 149, + 20, + 30, + -9, + -63 + ] + ], + [ + [ + 147, + 149, + 33, + 26, + -15, + -61 + ], + [ + 181, + 149, + 33, + 26, + -15, + -61 + ], + [ + 215, + 149, + 33, + 26, + -15, + -61 + ], + [ + 249, + 149, + 33, + 26, + -15, + -61 + ], + [ + 283, + 149, + 33, + 26, + -15, + -61 + ], + [ + 317, + 149, + 33, + 26, + -15, + -61 + ], + [ + 351, + 149, + 33, + 26, + -15, + -61 + ], + [ + 385, + 149, + 33, + 26, + -15, + -61 + ] + ], + [ + [ + 419, + 149, + 45, + 22, + -20, + -59 + ], + [ + 465, + 149, + 45, + 22, + -20, + -59 + ], + [ + 511, + 149, + 45, + 22, + -20, + -59 + ], + [ + 557, + 149, + 45, + 22, + -20, + -59 + ], + [ + 603, + 149, + 45, + 22, + -20, + -59 + ], + [ + 649, + 149, + 45, + 22, + -20, + -59 + ], + [ + 695, + 149, + 45, + 22, + -20, + -59 + ], + [ + 741, + 149, + 45, + 22, + -20, + -59 + ] + ], + [ + [ + 787, + 149, + 51, + 18, + -22, + -56 + ], + [ + 839, + 149, + 51, + 18, + -22, + -56 + ], + [ + 891, + 149, + 51, + 18, + -22, + -56 + ], + [ + 943, + 149, + 51, + 18, + -22, + -56 + ], + [ + 0, + 180, + 51, + 18, + -22, + -56 + ], + [ + 52, + 180, + 51, + 18, + -22, + -56 + ], + [ + 104, + 180, + 51, + 18, + -22, + -56 + ], + [ + 156, + 180, + 51, + 18, + -22, + -56 + ] + ], + [ + [ + 208, + 180, + 52, + 17, + -23, + -55 + ], + [ + 261, + 180, + 52, + 17, + -23, + -55 + ], + [ + 314, + 180, + 52, + 17, + -23, + -55 + ], + [ + 367, + 180, + 52, + 17, + -23, + -55 + ], + [ + 420, + 180, + 52, + 17, + -23, + -55 + ], + [ + 473, + 180, + 52, + 17, + -23, + -55 + ], + [ + 526, + 180, + 52, + 17, + -23, + -55 + ], + [ + 579, + 180, + 52, + 17, + -23, + -55 + ] + ], + [ + [ + 632, + 180, + 45, + 22, + -20, + -57 + ], + [ + 678, + 180, + 45, + 22, + -20, + -57 + ], + [ + 724, + 180, + 45, + 22, + -20, + -57 + ], + [ + 770, + 180, + 45, + 22, + -20, + -57 + ], + [ + 816, + 180, + 45, + 22, + -20, + -57 + ], + [ + 862, + 180, + 45, + 22, + -20, + -57 + ], + [ + 908, + 180, + 45, + 22, + -20, + -57 + ], + [ + 954, + 180, + 45, + 22, + -20, + -57 + ] + ], + [ + [ + 0, + 203, + 33, + 27, + -15, + -59 + ], + [ + 34, + 203, + 33, + 27, + -15, + -59 + ], + [ + 68, + 203, + 33, + 27, + -15, + -59 + ], + [ + 102, + 203, + 33, + 27, + -15, + -59 + ], + [ + 136, + 203, + 33, + 27, + -15, + -59 + ], + [ + 170, + 203, + 33, + 27, + -15, + -59 + ], + [ + 204, + 203, + 33, + 27, + -15, + -59 + ], + [ + 238, + 203, + 33, + 27, + -15, + -59 + ] + ], + [ + [ + 272, + 203, + 20, + 29, + -9, + -60 + ], + [ + 293, + 203, + 20, + 29, + -9, + -60 + ], + [ + 314, + 203, + 20, + 29, + -9, + -60 + ], + [ + 335, + 203, + 20, + 29, + -9, + -60 + ], + [ + 356, + 203, + 20, + 29, + -9, + -60 + ], + [ + 377, + 203, + 20, + 29, + -9, + -60 + ], + [ + 398, + 203, + 20, + 29, + -9, + -60 + ], + [ + 419, + 203, + 20, + 29, + -9, + -60 + ] + ], + [ + [ + 440, + 203, + 20, + 30, + -11, + -60 + ], + [ + 461, + 203, + 20, + 30, + -11, + -60 + ], + [ + 482, + 203, + 20, + 30, + -11, + -60 + ], + [ + 503, + 203, + 20, + 30, + -11, + -60 + ], + [ + 524, + 203, + 20, + 30, + -11, + -60 + ], + [ + 545, + 203, + 20, + 30, + -11, + -60 + ], + [ + 566, + 203, + 20, + 30, + -11, + -60 + ], + [ + 587, + 203, + 20, + 30, + -11, + -60 + ] + ], + [ + [ + 608, + 203, + 34, + 27, + -19, + -59 + ], + [ + 643, + 203, + 34, + 27, + -19, + -59 + ], + [ + 678, + 203, + 34, + 27, + -19, + -59 + ], + [ + 713, + 203, + 34, + 27, + -19, + -59 + ], + [ + 748, + 203, + 34, + 27, + -19, + -59 + ], + [ + 783, + 203, + 34, + 27, + -19, + -59 + ], + [ + 818, + 203, + 34, + 27, + -19, + -59 + ], + [ + 853, + 203, + 34, + 27, + -19, + -59 + ] + ], + [ + [ + 888, + 203, + 46, + 22, + -26, + -57 + ], + [ + 935, + 203, + 46, + 22, + -26, + -57 + ], + [ + 0, + 234, + 46, + 22, + -26, + -57 + ], + [ + 47, + 234, + 46, + 22, + -26, + -57 + ], + [ + 94, + 234, + 46, + 22, + -26, + -57 + ], + [ + 141, + 234, + 46, + 22, + -26, + -57 + ], + [ + 188, + 234, + 46, + 22, + -26, + -57 + ], + [ + 235, + 234, + 46, + 22, + -26, + -57 + ] + ], + [ + [ + 282, + 234, + 51, + 18, + -29, + -55 + ], + [ + 334, + 234, + 51, + 18, + -29, + -55 + ], + [ + 386, + 234, + 51, + 18, + -29, + -55 + ], + [ + 438, + 234, + 51, + 18, + -29, + -55 + ], + [ + 490, + 234, + 51, + 18, + -29, + -55 + ], + [ + 542, + 234, + 51, + 18, + -29, + -55 + ], + [ + 594, + 234, + 51, + 18, + -29, + -55 + ], + [ + 646, + 234, + 51, + 18, + -29, + -55 + ] + ], + [ + [ + 698, + 234, + 52, + 18, + -29, + -56 + ], + [ + 751, + 234, + 52, + 18, + -29, + -56 + ], + [ + 804, + 234, + 52, + 18, + -29, + -56 + ], + [ + 857, + 234, + 52, + 18, + -29, + -56 + ], + [ + 910, + 234, + 52, + 18, + -29, + -56 + ], + [ + 963, + 234, + 52, + 18, + -29, + -56 + ], + [ + 0, + 257, + 52, + 18, + -29, + -56 + ], + [ + 53, + 257, + 52, + 18, + -29, + -56 + ] + ], + [ + [ + 106, + 257, + 46, + 22, + -26, + -59 + ], + [ + 153, + 257, + 46, + 22, + -26, + -59 + ], + [ + 200, + 257, + 46, + 22, + -26, + -59 + ], + [ + 247, + 257, + 46, + 22, + -26, + -59 + ], + [ + 294, + 257, + 46, + 22, + -26, + -59 + ], + [ + 341, + 257, + 46, + 22, + -26, + -59 + ], + [ + 388, + 257, + 46, + 22, + -26, + -59 + ], + [ + 435, + 257, + 46, + 22, + -26, + -59 + ] + ], + [ + [ + 482, + 257, + 33, + 26, + -18, + -61 + ], + [ + 516, + 257, + 33, + 26, + -18, + -61 + ], + [ + 550, + 257, + 33, + 26, + -18, + -61 + ], + [ + 584, + 257, + 33, + 26, + -18, + -61 + ], + [ + 618, + 257, + 33, + 26, + -18, + -61 + ], + [ + 652, + 257, + 33, + 26, + -18, + -61 + ], + [ + 686, + 257, + 33, + 26, + -18, + -61 + ], + [ + 720, + 257, + 33, + 26, + -18, + -61 + ] + ], + [ + [ + 754, + 257, + 20, + 30, + -11, + -63 + ], + [ + 775, + 257, + 20, + 30, + -11, + -63 + ], + [ + 796, + 257, + 20, + 30, + -11, + -63 + ], + [ + 817, + 257, + 20, + 30, + -11, + -63 + ], + [ + 838, + 257, + 20, + 30, + -11, + -63 + ], + [ + 859, + 257, + 20, + 30, + -11, + -63 + ], + [ + 880, + 257, + 20, + 30, + -11, + -63 + ], + [ + 901, + 257, + 20, + 30, + -11, + -63 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/magicarrow.png b/public/missiles/magicarrow.png new file mode 100644 index 0000000..12cc329 Binary files /dev/null and b/public/missiles/magicarrow.png differ diff --git a/public/missiles/poisonnova.json b/public/missiles/poisonnova.json new file mode 100644 index 0000000..6a6a040 --- /dev/null +++ b/public/missiles/poisonnova.json @@ -0,0 +1,7755 @@ +{ + "name": "poisonnova", + "celFile": "poisonNova", + "width": 4096, + "height": 1369, + "directions": 32, + "framesPerDirection": 30, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 104, + 55, + -19, + -95 + ], + [ + 105, + 0, + 104, + 55, + -19, + -95 + ], + [ + 210, + 0, + 104, + 55, + -19, + -95 + ], + [ + 315, + 0, + 104, + 55, + -19, + -95 + ], + [ + 420, + 0, + 104, + 55, + -19, + -95 + ], + [ + 525, + 0, + 104, + 55, + -19, + -95 + ], + [ + 630, + 0, + 104, + 55, + -19, + -95 + ], + [ + 735, + 0, + 104, + 55, + -19, + -95 + ], + [ + 840, + 0, + 104, + 55, + -19, + -95 + ], + [ + 945, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1050, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1155, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1260, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1365, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1470, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1575, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1680, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1785, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1890, + 0, + 104, + 55, + -19, + -95 + ], + [ + 1995, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2100, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2205, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2310, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2415, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2520, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2625, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2730, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2835, + 0, + 104, + 55, + -19, + -95 + ], + [ + 2940, + 0, + 104, + 55, + -19, + -95 + ], + [ + 3045, + 0, + 104, + 55, + -19, + -95 + ] + ], + [ + [ + 3150, + 0, + 99, + 57, + -13, + -66 + ], + [ + 3250, + 0, + 99, + 57, + -13, + -66 + ], + [ + 3350, + 0, + 99, + 57, + -13, + -66 + ], + [ + 3450, + 0, + 99, + 57, + -13, + -66 + ], + [ + 3550, + 0, + 99, + 57, + -13, + -66 + ], + [ + 3650, + 0, + 99, + 57, + -13, + -66 + ], + [ + 3750, + 0, + 99, + 57, + -13, + -66 + ], + [ + 3850, + 0, + 99, + 57, + -13, + -66 + ], + [ + 3950, + 0, + 99, + 57, + -13, + -66 + ], + [ + 0, + 58, + 99, + 57, + -13, + -66 + ], + [ + 100, + 58, + 99, + 57, + -13, + -66 + ], + [ + 200, + 58, + 99, + 57, + -13, + -66 + ], + [ + 300, + 58, + 99, + 57, + -13, + -66 + ], + [ + 400, + 58, + 99, + 57, + -13, + -66 + ], + [ + 500, + 58, + 99, + 57, + -13, + -66 + ], + [ + 600, + 58, + 99, + 57, + -13, + -66 + ], + [ + 700, + 58, + 99, + 57, + -13, + -66 + ], + [ + 800, + 58, + 99, + 57, + -13, + -66 + ], + [ + 900, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1000, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1100, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1200, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1300, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1400, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1500, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1600, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1700, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1800, + 58, + 99, + 57, + -13, + -66 + ], + [ + 1900, + 58, + 99, + 57, + -13, + -66 + ], + [ + 2000, + 58, + 99, + 57, + -13, + -66 + ] + ], + [ + [ + 2100, + 58, + 99, + 56, + -86, + -64 + ], + [ + 2200, + 58, + 99, + 56, + -86, + -64 + ], + [ + 2300, + 58, + 99, + 56, + -86, + -64 + ], + [ + 2400, + 58, + 99, + 56, + -86, + -64 + ], + [ + 2500, + 58, + 99, + 56, + -86, + -64 + ], + [ + 2600, + 58, + 99, + 56, + -86, + -64 + ], + [ + 2700, + 58, + 99, + 56, + -86, + -64 + ], + [ + 2800, + 58, + 99, + 56, + -86, + -64 + ], + [ + 2900, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3000, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3100, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3200, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3300, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3400, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3500, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3600, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3700, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3800, + 58, + 99, + 56, + -86, + -64 + ], + [ + 3900, + 58, + 99, + 56, + -86, + -64 + ], + [ + 0, + 116, + 99, + 56, + -86, + -64 + ], + [ + 100, + 116, + 99, + 56, + -86, + -64 + ], + [ + 200, + 116, + 99, + 56, + -86, + -64 + ], + [ + 300, + 116, + 99, + 56, + -86, + -64 + ], + [ + 400, + 116, + 99, + 56, + -86, + -64 + ], + [ + 500, + 116, + 99, + 56, + -86, + -64 + ], + [ + 600, + 116, + 99, + 56, + -86, + -64 + ], + [ + 700, + 116, + 99, + 56, + -86, + -64 + ], + [ + 800, + 116, + 99, + 56, + -86, + -64 + ], + [ + 900, + 116, + 99, + 56, + -86, + -64 + ], + [ + 1000, + 116, + 99, + 56, + -86, + -64 + ] + ], + [ + [ + 1100, + 116, + 101, + 56, + -86, + -96 + ], + [ + 1202, + 116, + 101, + 56, + -86, + -96 + ], + [ + 1304, + 116, + 101, + 56, + -86, + -96 + ], + [ + 1406, + 116, + 101, + 56, + -86, + -96 + ], + [ + 1508, + 116, + 101, + 56, + -86, + -96 + ], + [ + 1610, + 116, + 101, + 56, + -86, + -96 + ], + [ + 1712, + 116, + 101, + 56, + -86, + -96 + ], + [ + 1814, + 116, + 101, + 56, + -86, + -96 + ], + [ + 1916, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2018, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2120, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2222, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2324, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2426, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2528, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2630, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2732, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2834, + 116, + 101, + 56, + -86, + -96 + ], + [ + 2936, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3038, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3140, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3242, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3344, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3446, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3548, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3650, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3752, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3854, + 116, + 101, + 56, + -86, + -96 + ], + [ + 3956, + 116, + 101, + 56, + -86, + -96 + ], + [ + 0, + 173, + 101, + 56, + -86, + -96 + ] + ], + [ + [ + 102, + 173, + 28, + 77, + -12, + -110 + ], + [ + 131, + 173, + 28, + 77, + -12, + -110 + ], + [ + 160, + 173, + 28, + 77, + -12, + -110 + ], + [ + 189, + 173, + 28, + 77, + -12, + -110 + ], + [ + 218, + 173, + 28, + 77, + -12, + -110 + ], + [ + 247, + 173, + 28, + 77, + -12, + -110 + ], + [ + 276, + 173, + 28, + 77, + -12, + -110 + ], + [ + 305, + 173, + 28, + 77, + -12, + -110 + ], + [ + 334, + 173, + 28, + 77, + -12, + -110 + ], + [ + 363, + 173, + 28, + 77, + -12, + -110 + ], + [ + 392, + 173, + 28, + 77, + -12, + -110 + ], + [ + 421, + 173, + 28, + 77, + -12, + -110 + ], + [ + 450, + 173, + 28, + 77, + -12, + -110 + ], + [ + 479, + 173, + 28, + 77, + -12, + -110 + ], + [ + 508, + 173, + 28, + 77, + -12, + -110 + ], + [ + 537, + 173, + 28, + 77, + -12, + -110 + ], + [ + 566, + 173, + 28, + 77, + -12, + -110 + ], + [ + 595, + 173, + 28, + 77, + -12, + -110 + ], + [ + 624, + 173, + 28, + 77, + -12, + -110 + ], + [ + 653, + 173, + 28, + 77, + -12, + -110 + ], + [ + 682, + 173, + 28, + 77, + -12, + -110 + ], + [ + 711, + 173, + 28, + 77, + -12, + -110 + ], + [ + 740, + 173, + 28, + 77, + -12, + -110 + ], + [ + 769, + 173, + 28, + 77, + -12, + -110 + ], + [ + 798, + 173, + 28, + 77, + -12, + -110 + ], + [ + 827, + 173, + 28, + 77, + -12, + -110 + ], + [ + 856, + 173, + 28, + 77, + -12, + -110 + ], + [ + 885, + 173, + 28, + 77, + -12, + -110 + ], + [ + 914, + 173, + 28, + 77, + -12, + -110 + ], + [ + 943, + 173, + 28, + 77, + -12, + -110 + ] + ], + [ + [ + 972, + 173, + 138, + 29, + -20, + -66 + ], + [ + 1111, + 173, + 138, + 29, + -20, + -66 + ], + [ + 1250, + 173, + 138, + 29, + -20, + -66 + ], + [ + 1389, + 173, + 138, + 29, + -20, + -66 + ], + [ + 1528, + 173, + 138, + 29, + -20, + -66 + ], + [ + 1667, + 173, + 138, + 29, + -20, + -66 + ], + [ + 1806, + 173, + 138, + 29, + -20, + -66 + ], + [ + 1945, + 173, + 138, + 29, + -20, + -66 + ], + [ + 2084, + 173, + 138, + 29, + -20, + -66 + ], + [ + 2223, + 173, + 138, + 29, + -20, + -66 + ], + [ + 2362, + 173, + 138, + 29, + -20, + -66 + ], + [ + 2501, + 173, + 138, + 29, + -20, + -66 + ], + [ + 2640, + 173, + 138, + 29, + -20, + -66 + ], + [ + 2779, + 173, + 138, + 29, + -20, + -66 + ], + [ + 2918, + 173, + 138, + 29, + -20, + -66 + ], + [ + 3057, + 173, + 138, + 29, + -20, + -66 + ], + [ + 3196, + 173, + 138, + 29, + -20, + -66 + ], + [ + 3335, + 173, + 138, + 29, + -20, + -66 + ], + [ + 3474, + 173, + 138, + 29, + -20, + -66 + ], + [ + 3613, + 173, + 138, + 29, + -20, + -66 + ], + [ + 3752, + 173, + 138, + 29, + -20, + -66 + ], + [ + 3891, + 173, + 138, + 29, + -20, + -66 + ], + [ + 0, + 251, + 138, + 29, + -20, + -66 + ], + [ + 139, + 251, + 138, + 29, + -20, + -66 + ], + [ + 278, + 251, + 138, + 29, + -20, + -66 + ], + [ + 417, + 251, + 138, + 29, + -20, + -66 + ], + [ + 556, + 251, + 138, + 29, + -20, + -66 + ], + [ + 695, + 251, + 138, + 29, + -20, + -66 + ], + [ + 834, + 251, + 138, + 29, + -20, + -66 + ], + [ + 973, + 251, + 138, + 29, + -20, + -66 + ] + ], + [ + [ + 1112, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1141, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1170, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1199, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1228, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1257, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1286, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1315, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1344, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1373, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1402, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1431, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1460, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1489, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1518, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1547, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1576, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1605, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1634, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1663, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1692, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1721, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1750, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1779, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1808, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1837, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1866, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1895, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1924, + 251, + 28, + 72, + -16, + -64 + ], + [ + 1953, + 251, + 28, + 72, + -16, + -64 + ] + ], + [ + [ + 1982, + 251, + 138, + 28, + -118, + -66 + ], + [ + 2121, + 251, + 138, + 28, + -118, + -66 + ], + [ + 2260, + 251, + 138, + 28, + -118, + -66 + ], + [ + 2399, + 251, + 138, + 28, + -118, + -66 + ], + [ + 2538, + 251, + 138, + 28, + -118, + -66 + ], + [ + 2677, + 251, + 138, + 28, + -118, + -66 + ], + [ + 2816, + 251, + 138, + 28, + -118, + -66 + ], + [ + 2955, + 251, + 138, + 28, + -118, + -66 + ], + [ + 3094, + 251, + 138, + 28, + -118, + -66 + ], + [ + 3233, + 251, + 138, + 28, + -118, + -66 + ], + [ + 3372, + 251, + 138, + 28, + -118, + -66 + ], + [ + 3511, + 251, + 138, + 28, + -118, + -66 + ], + [ + 3650, + 251, + 138, + 28, + -118, + -66 + ], + [ + 3789, + 251, + 138, + 28, + -118, + -66 + ], + [ + 3928, + 251, + 138, + 28, + -118, + -66 + ], + [ + 0, + 324, + 138, + 28, + -118, + -66 + ], + [ + 139, + 324, + 138, + 28, + -118, + -66 + ], + [ + 278, + 324, + 138, + 28, + -118, + -66 + ], + [ + 417, + 324, + 138, + 28, + -118, + -66 + ], + [ + 556, + 324, + 138, + 28, + -118, + -66 + ], + [ + 695, + 324, + 138, + 28, + -118, + -66 + ], + [ + 834, + 324, + 138, + 28, + -118, + -66 + ], + [ + 973, + 324, + 138, + 28, + -118, + -66 + ], + [ + 1112, + 324, + 138, + 28, + -118, + -66 + ], + [ + 1251, + 324, + 138, + 28, + -118, + -66 + ], + [ + 1390, + 324, + 138, + 28, + -118, + -66 + ], + [ + 1529, + 324, + 138, + 28, + -118, + -66 + ], + [ + 1668, + 324, + 138, + 28, + -118, + -66 + ], + [ + 1807, + 324, + 138, + 28, + -118, + -66 + ], + [ + 1946, + 324, + 138, + 28, + -118, + -66 + ] + ], + [ + [ + 2085, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2152, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2219, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2286, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2353, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2420, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2487, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2554, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2621, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2688, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2755, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2822, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2889, + 324, + 66, + 67, + -15, + -106 + ], + [ + 2956, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3023, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3090, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3157, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3224, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3291, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3358, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3425, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3492, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3559, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3626, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3693, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3760, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3827, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3894, + 324, + 66, + 67, + -15, + -106 + ], + [ + 3961, + 324, + 66, + 67, + -15, + -106 + ], + [ + 4028, + 324, + 66, + 67, + -15, + -106 + ] + ], + [ + [ + 0, + 392, + 131, + 36, + -20, + -76 + ], + [ + 132, + 392, + 131, + 36, + -20, + -76 + ], + [ + 264, + 392, + 131, + 36, + -20, + -76 + ], + [ + 396, + 392, + 131, + 36, + -20, + -76 + ], + [ + 528, + 392, + 131, + 36, + -20, + -76 + ], + [ + 660, + 392, + 131, + 36, + -20, + -76 + ], + [ + 792, + 392, + 131, + 36, + -20, + -76 + ], + [ + 924, + 392, + 131, + 36, + -20, + -76 + ], + [ + 1056, + 392, + 131, + 36, + -20, + -76 + ], + [ + 1188, + 392, + 131, + 36, + -20, + -76 + ], + [ + 1320, + 392, + 131, + 36, + -20, + -76 + ], + [ + 1452, + 392, + 131, + 36, + -20, + -76 + ], + [ + 1584, + 392, + 131, + 36, + -20, + -76 + ], + [ + 1716, + 392, + 131, + 36, + -20, + -76 + ], + [ + 1848, + 392, + 131, + 36, + -20, + -76 + ], + [ + 1980, + 392, + 131, + 36, + -20, + -76 + ], + [ + 2112, + 392, + 131, + 36, + -20, + -76 + ], + [ + 2244, + 392, + 131, + 36, + -20, + -76 + ], + [ + 2376, + 392, + 131, + 36, + -20, + -76 + ], + [ + 2508, + 392, + 131, + 36, + -20, + -76 + ], + [ + 2640, + 392, + 131, + 36, + -20, + -76 + ], + [ + 2772, + 392, + 131, + 36, + -20, + -76 + ], + [ + 2904, + 392, + 131, + 36, + -20, + -76 + ], + [ + 3036, + 392, + 131, + 36, + -20, + -76 + ], + [ + 3168, + 392, + 131, + 36, + -20, + -76 + ], + [ + 3300, + 392, + 131, + 36, + -20, + -76 + ], + [ + 3432, + 392, + 131, + 36, + -20, + -76 + ], + [ + 3564, + 392, + 131, + 36, + -20, + -76 + ], + [ + 3696, + 392, + 131, + 36, + -20, + -76 + ], + [ + 3828, + 392, + 131, + 36, + -20, + -76 + ] + ], + [ + [ + 3960, + 392, + 130, + 38, + -22, + -63 + ], + [ + 0, + 431, + 130, + 38, + -22, + -63 + ], + [ + 131, + 431, + 130, + 38, + -22, + -63 + ], + [ + 262, + 431, + 130, + 38, + -22, + -63 + ], + [ + 393, + 431, + 130, + 38, + -22, + -63 + ], + [ + 524, + 431, + 130, + 38, + -22, + -63 + ], + [ + 655, + 431, + 130, + 38, + -22, + -63 + ], + [ + 786, + 431, + 130, + 38, + -22, + -63 + ], + [ + 917, + 431, + 130, + 38, + -22, + -63 + ], + [ + 1048, + 431, + 130, + 38, + -22, + -63 + ], + [ + 1179, + 431, + 130, + 38, + -22, + -63 + ], + [ + 1310, + 431, + 130, + 38, + -22, + -63 + ], + [ + 1441, + 431, + 130, + 38, + -22, + -63 + ], + [ + 1572, + 431, + 130, + 38, + -22, + -63 + ], + [ + 1703, + 431, + 130, + 38, + -22, + -63 + ], + [ + 1834, + 431, + 130, + 38, + -22, + -63 + ], + [ + 1965, + 431, + 130, + 38, + -22, + -63 + ], + [ + 2096, + 431, + 130, + 38, + -22, + -63 + ], + [ + 2227, + 431, + 130, + 38, + -22, + -63 + ], + [ + 2358, + 431, + 130, + 38, + -22, + -63 + ], + [ + 2489, + 431, + 130, + 38, + -22, + -63 + ], + [ + 2620, + 431, + 130, + 38, + -22, + -63 + ], + [ + 2751, + 431, + 130, + 38, + -22, + -63 + ], + [ + 2882, + 431, + 130, + 38, + -22, + -63 + ], + [ + 3013, + 431, + 130, + 38, + -22, + -63 + ], + [ + 3144, + 431, + 130, + 38, + -22, + -63 + ], + [ + 3275, + 431, + 130, + 38, + -22, + -63 + ], + [ + 3406, + 431, + 130, + 38, + -22, + -63 + ], + [ + 3537, + 431, + 130, + 38, + -22, + -63 + ], + [ + 3668, + 431, + 130, + 38, + -22, + -63 + ] + ], + [ + [ + 3799, + 431, + 67, + 67, + -19, + -63 + ], + [ + 3867, + 431, + 67, + 67, + -19, + -63 + ], + [ + 3935, + 431, + 67, + 67, + -19, + -63 + ], + [ + 4003, + 431, + 67, + 67, + -19, + -63 + ], + [ + 0, + 499, + 67, + 67, + -19, + -63 + ], + [ + 68, + 499, + 67, + 67, + -19, + -63 + ], + [ + 136, + 499, + 67, + 67, + -19, + -63 + ], + [ + 204, + 499, + 67, + 67, + -19, + -63 + ], + [ + 272, + 499, + 67, + 67, + -19, + -63 + ], + [ + 340, + 499, + 67, + 67, + -19, + -63 + ], + [ + 408, + 499, + 67, + 67, + -19, + -63 + ], + [ + 476, + 499, + 67, + 67, + -19, + -63 + ], + [ + 544, + 499, + 67, + 67, + -19, + -63 + ], + [ + 612, + 499, + 67, + 67, + -19, + -63 + ], + [ + 680, + 499, + 67, + 67, + -19, + -63 + ], + [ + 748, + 499, + 67, + 67, + -19, + -63 + ], + [ + 816, + 499, + 67, + 67, + -19, + -63 + ], + [ + 884, + 499, + 67, + 67, + -19, + -63 + ], + [ + 952, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1020, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1088, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1156, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1224, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1292, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1360, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1428, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1496, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1564, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1632, + 499, + 67, + 67, + -19, + -63 + ], + [ + 1700, + 499, + 67, + 67, + -19, + -63 + ] + ], + [ + [ + 1768, + 499, + 62, + 73, + -51, + -70 + ], + [ + 1831, + 499, + 62, + 73, + -51, + -70 + ], + [ + 1894, + 499, + 62, + 73, + -51, + -70 + ], + [ + 1957, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2020, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2083, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2146, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2209, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2272, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2335, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2398, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2461, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2524, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2587, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2650, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2713, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2776, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2839, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2902, + 499, + 62, + 73, + -51, + -70 + ], + [ + 2965, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3028, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3091, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3154, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3217, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3280, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3343, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3406, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3469, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3532, + 499, + 62, + 73, + -51, + -70 + ], + [ + 3595, + 499, + 62, + 73, + -51, + -70 + ] + ], + [ + [ + 3658, + 499, + 127, + 39, + -110, + -65 + ], + [ + 3786, + 499, + 127, + 39, + -110, + -65 + ], + [ + 3914, + 499, + 127, + 39, + -110, + -65 + ], + [ + 0, + 573, + 127, + 39, + -110, + -65 + ], + [ + 128, + 573, + 127, + 39, + -110, + -65 + ], + [ + 256, + 573, + 127, + 39, + -110, + -65 + ], + [ + 384, + 573, + 127, + 39, + -110, + -65 + ], + [ + 512, + 573, + 127, + 39, + -110, + -65 + ], + [ + 640, + 573, + 127, + 39, + -110, + -65 + ], + [ + 768, + 573, + 127, + 39, + -110, + -65 + ], + [ + 896, + 573, + 127, + 39, + -110, + -65 + ], + [ + 1024, + 573, + 127, + 39, + -110, + -65 + ], + [ + 1152, + 573, + 127, + 39, + -110, + -65 + ], + [ + 1280, + 573, + 127, + 39, + -110, + -65 + ], + [ + 1408, + 573, + 127, + 39, + -110, + -65 + ], + [ + 1536, + 573, + 127, + 39, + -110, + -65 + ], + [ + 1664, + 573, + 127, + 39, + -110, + -65 + ], + [ + 1792, + 573, + 127, + 39, + -110, + -65 + ], + [ + 1920, + 573, + 127, + 39, + -110, + -65 + ], + [ + 2048, + 573, + 127, + 39, + -110, + -65 + ], + [ + 2176, + 573, + 127, + 39, + -110, + -65 + ], + [ + 2304, + 573, + 127, + 39, + -110, + -65 + ], + [ + 2432, + 573, + 127, + 39, + -110, + -65 + ], + [ + 2560, + 573, + 127, + 39, + -110, + -65 + ], + [ + 2688, + 573, + 127, + 39, + -110, + -65 + ], + [ + 2816, + 573, + 127, + 39, + -110, + -65 + ], + [ + 2944, + 573, + 127, + 39, + -110, + -65 + ], + [ + 3072, + 573, + 127, + 39, + -110, + -65 + ], + [ + 3200, + 573, + 127, + 39, + -110, + -65 + ], + [ + 3328, + 573, + 127, + 39, + -110, + -65 + ] + ], + [ + [ + 3456, + 573, + 129, + 39, + -110, + -79 + ], + [ + 3586, + 573, + 129, + 39, + -110, + -79 + ], + [ + 3716, + 573, + 129, + 39, + -110, + -79 + ], + [ + 3846, + 573, + 129, + 39, + -110, + -79 + ], + [ + 0, + 613, + 129, + 39, + -110, + -79 + ], + [ + 130, + 613, + 129, + 39, + -110, + -79 + ], + [ + 260, + 613, + 129, + 39, + -110, + -79 + ], + [ + 390, + 613, + 129, + 39, + -110, + -79 + ], + [ + 520, + 613, + 129, + 39, + -110, + -79 + ], + [ + 650, + 613, + 129, + 39, + -110, + -79 + ], + [ + 780, + 613, + 129, + 39, + -110, + -79 + ], + [ + 910, + 613, + 129, + 39, + -110, + -79 + ], + [ + 1040, + 613, + 129, + 39, + -110, + -79 + ], + [ + 1170, + 613, + 129, + 39, + -110, + -79 + ], + [ + 1300, + 613, + 129, + 39, + -110, + -79 + ], + [ + 1430, + 613, + 129, + 39, + -110, + -79 + ], + [ + 1560, + 613, + 129, + 39, + -110, + -79 + ], + [ + 1690, + 613, + 129, + 39, + -110, + -79 + ], + [ + 1820, + 613, + 129, + 39, + -110, + -79 + ], + [ + 1950, + 613, + 129, + 39, + -110, + -79 + ], + [ + 2080, + 613, + 129, + 39, + -110, + -79 + ], + [ + 2210, + 613, + 129, + 39, + -110, + -79 + ], + [ + 2340, + 613, + 129, + 39, + -110, + -79 + ], + [ + 2470, + 613, + 129, + 39, + -110, + -79 + ], + [ + 2600, + 613, + 129, + 39, + -110, + -79 + ], + [ + 2730, + 613, + 129, + 39, + -110, + -79 + ], + [ + 2860, + 613, + 129, + 39, + -110, + -79 + ], + [ + 2990, + 613, + 129, + 39, + -110, + -79 + ], + [ + 3120, + 613, + 129, + 39, + -110, + -79 + ], + [ + 3250, + 613, + 129, + 39, + -110, + -79 + ] + ], + [ + [ + 3380, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3443, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3506, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3569, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3632, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3695, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3758, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3821, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3884, + 613, + 62, + 69, + -49, + -107 + ], + [ + 3947, + 613, + 62, + 69, + -49, + -107 + ], + [ + 4010, + 613, + 62, + 69, + -49, + -107 + ], + [ + 0, + 683, + 62, + 69, + -49, + -107 + ], + [ + 63, + 683, + 62, + 69, + -49, + -107 + ], + [ + 126, + 683, + 62, + 69, + -49, + -107 + ], + [ + 189, + 683, + 62, + 69, + -49, + -107 + ], + [ + 252, + 683, + 62, + 69, + -49, + -107 + ], + [ + 315, + 683, + 62, + 69, + -49, + -107 + ], + [ + 378, + 683, + 62, + 69, + -49, + -107 + ], + [ + 441, + 683, + 62, + 69, + -49, + -107 + ], + [ + 504, + 683, + 62, + 69, + -49, + -107 + ], + [ + 567, + 683, + 62, + 69, + -49, + -107 + ], + [ + 630, + 683, + 62, + 69, + -49, + -107 + ], + [ + 693, + 683, + 62, + 69, + -49, + -107 + ], + [ + 756, + 683, + 62, + 69, + -49, + -107 + ], + [ + 819, + 683, + 62, + 69, + -49, + -107 + ], + [ + 882, + 683, + 62, + 69, + -49, + -107 + ], + [ + 945, + 683, + 62, + 69, + -49, + -107 + ], + [ + 1008, + 683, + 62, + 69, + -49, + -107 + ], + [ + 1071, + 683, + 62, + 69, + -49, + -107 + ], + [ + 1134, + 683, + 62, + 69, + -49, + -107 + ] + ], + [ + [ + 1197, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1237, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1277, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1317, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1357, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1397, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1437, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1477, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1517, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1557, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1597, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1637, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1677, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1717, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1757, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1797, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1837, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1877, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1917, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1957, + 683, + 39, + 76, + -11, + -109 + ], + [ + 1997, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2037, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2077, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2117, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2157, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2197, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2237, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2277, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2317, + 683, + 39, + 76, + -11, + -109 + ], + [ + 2357, + 683, + 39, + 76, + -11, + -109 + ] + ], + [ + [ + 2397, + 683, + 82, + 63, + -12, + -98 + ], + [ + 2480, + 683, + 82, + 63, + -12, + -98 + ], + [ + 2563, + 683, + 82, + 63, + -12, + -98 + ], + [ + 2646, + 683, + 82, + 63, + -12, + -98 + ], + [ + 2729, + 683, + 82, + 63, + -12, + -98 + ], + [ + 2812, + 683, + 82, + 63, + -12, + -98 + ], + [ + 2895, + 683, + 82, + 63, + -12, + -98 + ], + [ + 2978, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3061, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3144, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3227, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3310, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3393, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3476, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3559, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3642, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3725, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3808, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3891, + 683, + 82, + 63, + -12, + -98 + ], + [ + 3974, + 683, + 82, + 63, + -12, + -98 + ], + [ + 0, + 760, + 82, + 63, + -12, + -98 + ], + [ + 83, + 760, + 82, + 63, + -12, + -98 + ], + [ + 166, + 760, + 82, + 63, + -12, + -98 + ], + [ + 249, + 760, + 82, + 63, + -12, + -98 + ], + [ + 332, + 760, + 82, + 63, + -12, + -98 + ], + [ + 415, + 760, + 82, + 63, + -12, + -98 + ], + [ + 498, + 760, + 82, + 63, + -12, + -98 + ], + [ + 581, + 760, + 82, + 63, + -12, + -98 + ], + [ + 664, + 760, + 82, + 63, + -12, + -98 + ], + [ + 747, + 760, + 82, + 63, + -12, + -98 + ] + ], + [ + [ + 830, + 760, + 122, + 47, + -21, + -86 + ], + [ + 953, + 760, + 122, + 47, + -21, + -86 + ], + [ + 1076, + 760, + 122, + 47, + -21, + -86 + ], + [ + 1199, + 760, + 122, + 47, + -21, + -86 + ], + [ + 1322, + 760, + 122, + 47, + -21, + -86 + ], + [ + 1445, + 760, + 122, + 47, + -21, + -86 + ], + [ + 1568, + 760, + 122, + 47, + -21, + -86 + ], + [ + 1691, + 760, + 122, + 47, + -21, + -86 + ], + [ + 1814, + 760, + 122, + 47, + -21, + -86 + ], + [ + 1937, + 760, + 122, + 47, + -21, + -86 + ], + [ + 2060, + 760, + 122, + 47, + -21, + -86 + ], + [ + 2183, + 760, + 122, + 47, + -21, + -86 + ], + [ + 2306, + 760, + 122, + 47, + -21, + -86 + ], + [ + 2429, + 760, + 122, + 47, + -21, + -86 + ], + [ + 2552, + 760, + 122, + 47, + -21, + -86 + ], + [ + 2675, + 760, + 122, + 47, + -21, + -86 + ], + [ + 2798, + 760, + 122, + 47, + -21, + -86 + ], + [ + 2921, + 760, + 122, + 47, + -21, + -86 + ], + [ + 3044, + 760, + 122, + 47, + -21, + -86 + ], + [ + 3167, + 760, + 122, + 47, + -21, + -86 + ], + [ + 3290, + 760, + 122, + 47, + -21, + -86 + ], + [ + 3413, + 760, + 122, + 47, + -21, + -86 + ], + [ + 3536, + 760, + 122, + 47, + -21, + -86 + ], + [ + 3659, + 760, + 122, + 47, + -21, + -86 + ], + [ + 3782, + 760, + 122, + 47, + -21, + -86 + ], + [ + 3905, + 760, + 122, + 47, + -21, + -86 + ], + [ + 0, + 824, + 122, + 47, + -21, + -86 + ], + [ + 123, + 824, + 122, + 47, + -21, + -86 + ], + [ + 246, + 824, + 122, + 47, + -21, + -86 + ], + [ + 369, + 824, + 122, + 47, + -21, + -86 + ] + ], + [ + [ + 492, + 824, + 138, + 30, + -21, + -69 + ], + [ + 631, + 824, + 138, + 30, + -21, + -69 + ], + [ + 770, + 824, + 138, + 30, + -21, + -69 + ], + [ + 909, + 824, + 138, + 30, + -21, + -69 + ], + [ + 1048, + 824, + 138, + 30, + -21, + -69 + ], + [ + 1187, + 824, + 138, + 30, + -21, + -69 + ], + [ + 1326, + 824, + 138, + 30, + -21, + -69 + ], + [ + 1465, + 824, + 138, + 30, + -21, + -69 + ], + [ + 1604, + 824, + 138, + 30, + -21, + -69 + ], + [ + 1743, + 824, + 138, + 30, + -21, + -69 + ], + [ + 1882, + 824, + 138, + 30, + -21, + -69 + ], + [ + 2021, + 824, + 138, + 30, + -21, + -69 + ], + [ + 2160, + 824, + 138, + 30, + -21, + -69 + ], + [ + 2299, + 824, + 138, + 30, + -21, + -69 + ], + [ + 2438, + 824, + 138, + 30, + -21, + -69 + ], + [ + 2577, + 824, + 138, + 30, + -21, + -69 + ], + [ + 2716, + 824, + 138, + 30, + -21, + -69 + ], + [ + 2855, + 824, + 138, + 30, + -21, + -69 + ], + [ + 2994, + 824, + 138, + 30, + -21, + -69 + ], + [ + 3133, + 824, + 138, + 30, + -21, + -69 + ], + [ + 3272, + 824, + 138, + 30, + -21, + -69 + ], + [ + 3411, + 824, + 138, + 30, + -21, + -69 + ], + [ + 3550, + 824, + 138, + 30, + -21, + -69 + ], + [ + 3689, + 824, + 138, + 30, + -21, + -69 + ], + [ + 3828, + 824, + 138, + 30, + -21, + -69 + ], + [ + 0, + 872, + 138, + 30, + -21, + -69 + ], + [ + 139, + 872, + 138, + 30, + -21, + -69 + ], + [ + 278, + 872, + 138, + 30, + -21, + -69 + ], + [ + 417, + 872, + 138, + 30, + -21, + -69 + ], + [ + 556, + 872, + 138, + 30, + -21, + -69 + ] + ], + [ + [ + 695, + 872, + 135, + 34, + -20, + -67 + ], + [ + 831, + 872, + 135, + 34, + -20, + -67 + ], + [ + 967, + 872, + 135, + 34, + -20, + -67 + ], + [ + 1103, + 872, + 135, + 34, + -20, + -67 + ], + [ + 1239, + 872, + 135, + 34, + -20, + -67 + ], + [ + 1375, + 872, + 135, + 34, + -20, + -67 + ], + [ + 1511, + 872, + 135, + 34, + -20, + -67 + ], + [ + 1647, + 872, + 135, + 34, + -20, + -67 + ], + [ + 1783, + 872, + 135, + 34, + -20, + -67 + ], + [ + 1919, + 872, + 135, + 34, + -20, + -67 + ], + [ + 2055, + 872, + 135, + 34, + -20, + -67 + ], + [ + 2191, + 872, + 135, + 34, + -20, + -67 + ], + [ + 2327, + 872, + 135, + 34, + -20, + -67 + ], + [ + 2463, + 872, + 135, + 34, + -20, + -67 + ], + [ + 2599, + 872, + 135, + 34, + -20, + -67 + ], + [ + 2735, + 872, + 135, + 34, + -20, + -67 + ], + [ + 2871, + 872, + 135, + 34, + -20, + -67 + ], + [ + 3007, + 872, + 135, + 34, + -20, + -67 + ], + [ + 3143, + 872, + 135, + 34, + -20, + -67 + ], + [ + 3279, + 872, + 135, + 34, + -20, + -67 + ], + [ + 3415, + 872, + 135, + 34, + -20, + -67 + ], + [ + 3551, + 872, + 135, + 34, + -20, + -67 + ], + [ + 3687, + 872, + 135, + 34, + -20, + -67 + ], + [ + 3823, + 872, + 135, + 34, + -20, + -67 + ], + [ + 3959, + 872, + 135, + 34, + -20, + -67 + ], + [ + 0, + 907, + 135, + 34, + -20, + -67 + ], + [ + 136, + 907, + 135, + 34, + -20, + -67 + ], + [ + 272, + 907, + 135, + 34, + -20, + -67 + ], + [ + 408, + 907, + 135, + 34, + -20, + -67 + ], + [ + 544, + 907, + 135, + 34, + -20, + -67 + ] + ], + [ + [ + 680, + 907, + 116, + 47, + -16, + -64 + ], + [ + 797, + 907, + 116, + 47, + -16, + -64 + ], + [ + 914, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1031, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1148, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1265, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1382, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1499, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1616, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1733, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1850, + 907, + 116, + 47, + -16, + -64 + ], + [ + 1967, + 907, + 116, + 47, + -16, + -64 + ], + [ + 2084, + 907, + 116, + 47, + -16, + -64 + ], + [ + 2201, + 907, + 116, + 47, + -16, + -64 + ], + [ + 2318, + 907, + 116, + 47, + -16, + -64 + ], + [ + 2435, + 907, + 116, + 47, + -16, + -64 + ], + [ + 2552, + 907, + 116, + 47, + -16, + -64 + ], + [ + 2669, + 907, + 116, + 47, + -16, + -64 + ], + [ + 2786, + 907, + 116, + 47, + -16, + -64 + ], + [ + 2903, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3020, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3137, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3254, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3371, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3488, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3605, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3722, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3839, + 907, + 116, + 47, + -16, + -64 + ], + [ + 3956, + 907, + 116, + 47, + -16, + -64 + ], + [ + 0, + 955, + 116, + 47, + -16, + -64 + ] + ], + [ + [ + 117, + 955, + 85, + 63, + -17, + -64 + ], + [ + 203, + 955, + 85, + 63, + -17, + -64 + ], + [ + 289, + 955, + 85, + 63, + -17, + -64 + ], + [ + 375, + 955, + 85, + 63, + -17, + -64 + ], + [ + 461, + 955, + 85, + 63, + -17, + -64 + ], + [ + 547, + 955, + 85, + 63, + -17, + -64 + ], + [ + 633, + 955, + 85, + 63, + -17, + -64 + ], + [ + 719, + 955, + 85, + 63, + -17, + -64 + ], + [ + 805, + 955, + 85, + 63, + -17, + -64 + ], + [ + 891, + 955, + 85, + 63, + -17, + -64 + ], + [ + 977, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1063, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1149, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1235, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1321, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1407, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1493, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1579, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1665, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1751, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1837, + 955, + 85, + 63, + -17, + -64 + ], + [ + 1923, + 955, + 85, + 63, + -17, + -64 + ], + [ + 2009, + 955, + 85, + 63, + -17, + -64 + ], + [ + 2095, + 955, + 85, + 63, + -17, + -64 + ], + [ + 2181, + 955, + 85, + 63, + -17, + -64 + ], + [ + 2267, + 955, + 85, + 63, + -17, + -64 + ], + [ + 2353, + 955, + 85, + 63, + -17, + -64 + ], + [ + 2439, + 955, + 85, + 63, + -17, + -64 + ], + [ + 2525, + 955, + 85, + 63, + -17, + -64 + ], + [ + 2611, + 955, + 85, + 63, + -17, + -64 + ] + ], + [ + [ + 2697, + 955, + 39, + 74, + -13, + -70 + ], + [ + 2737, + 955, + 39, + 74, + -13, + -70 + ], + [ + 2777, + 955, + 39, + 74, + -13, + -70 + ], + [ + 2817, + 955, + 39, + 74, + -13, + -70 + ], + [ + 2857, + 955, + 39, + 74, + -13, + -70 + ], + [ + 2897, + 955, + 39, + 74, + -13, + -70 + ], + [ + 2937, + 955, + 39, + 74, + -13, + -70 + ], + [ + 2977, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3017, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3057, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3097, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3137, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3177, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3217, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3257, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3297, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3337, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3377, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3417, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3457, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3497, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3537, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3577, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3617, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3657, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3697, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3737, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3777, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3817, + 955, + 39, + 74, + -13, + -70 + ], + [ + 3857, + 955, + 39, + 74, + -13, + -70 + ] + ], + [ + [ + 3897, + 955, + 44, + 69, + -29, + -66 + ], + [ + 3942, + 955, + 44, + 69, + -29, + -66 + ], + [ + 3987, + 955, + 44, + 69, + -29, + -66 + ], + [ + 4032, + 955, + 44, + 69, + -29, + -66 + ], + [ + 0, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 45, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 90, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 135, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 180, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 225, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 270, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 315, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 360, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 405, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 450, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 495, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 540, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 585, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 630, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 675, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 720, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 765, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 810, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 855, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 900, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 945, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 990, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 1035, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 1080, + 1030, + 44, + 69, + -29, + -66 + ], + [ + 1125, + 1030, + 44, + 69, + -29, + -66 + ] + ], + [ + [ + 1170, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1254, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1338, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1422, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1506, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1590, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1674, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1758, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1842, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 1926, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2010, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2094, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2178, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2262, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2346, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2430, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2514, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2598, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2682, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2766, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2850, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 2934, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 3018, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 3102, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 3186, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 3270, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 3354, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 3438, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 3522, + 1030, + 83, + 66, + -70, + -70 + ], + [ + 3606, + 1030, + 83, + 66, + -70, + -70 + ] + ], + [ + [ + 3690, + 1030, + 119, + 49, + -99, + -67 + ], + [ + 3810, + 1030, + 119, + 49, + -99, + -67 + ], + [ + 3930, + 1030, + 119, + 49, + -99, + -67 + ], + [ + 0, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 120, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 240, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 360, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 480, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 600, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 720, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 840, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 960, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 1080, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 1200, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 1320, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 1440, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 1560, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 1680, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 1800, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 1920, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 2040, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 2160, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 2280, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 2400, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 2520, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 2640, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 2760, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 2880, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 3000, + 1100, + 119, + 49, + -99, + -67 + ], + [ + 3120, + 1100, + 119, + 49, + -99, + -67 + ] + ], + [ + [ + 3240, + 1100, + 135, + 33, + -116, + -67 + ], + [ + 3376, + 1100, + 135, + 33, + -116, + -67 + ], + [ + 3512, + 1100, + 135, + 33, + -116, + -67 + ], + [ + 3648, + 1100, + 135, + 33, + -116, + -67 + ], + [ + 3784, + 1100, + 135, + 33, + -116, + -67 + ], + [ + 3920, + 1100, + 135, + 33, + -116, + -67 + ], + [ + 0, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 136, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 272, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 408, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 544, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 680, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 816, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 952, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 1088, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 1224, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 1360, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 1496, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 1632, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 1768, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 1904, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 2040, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 2176, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 2312, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 2448, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 2584, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 2720, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 2856, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 2992, + 1150, + 135, + 33, + -116, + -67 + ], + [ + 3128, + 1150, + 135, + 33, + -116, + -67 + ] + ], + [ + [ + 3264, + 1150, + 137, + 33, + -116, + -70 + ], + [ + 3402, + 1150, + 137, + 33, + -116, + -70 + ], + [ + 3540, + 1150, + 137, + 33, + -116, + -70 + ], + [ + 3678, + 1150, + 137, + 33, + -116, + -70 + ], + [ + 3816, + 1150, + 137, + 33, + -116, + -70 + ], + [ + 3954, + 1150, + 137, + 33, + -116, + -70 + ], + [ + 0, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 138, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 276, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 414, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 552, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 690, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 828, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 966, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 1104, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 1242, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 1380, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 1518, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 1656, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 1794, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 1932, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 2070, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 2208, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 2346, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 2484, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 2622, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 2760, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 2898, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 3036, + 1184, + 137, + 33, + -116, + -70 + ], + [ + 3174, + 1184, + 137, + 33, + -116, + -70 + ] + ], + [ + [ + 3312, + 1184, + 121, + 47, + -99, + -86 + ], + [ + 3434, + 1184, + 121, + 47, + -99, + -86 + ], + [ + 3556, + 1184, + 121, + 47, + -99, + -86 + ], + [ + 3678, + 1184, + 121, + 47, + -99, + -86 + ], + [ + 3800, + 1184, + 121, + 47, + -99, + -86 + ], + [ + 3922, + 1184, + 121, + 47, + -99, + -86 + ], + [ + 0, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 122, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 244, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 366, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 488, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 610, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 732, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 854, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 976, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 1098, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 1220, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 1342, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 1464, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 1586, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 1708, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 1830, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 1952, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 2074, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 2196, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 2318, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 2440, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 2562, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 2684, + 1232, + 121, + 47, + -99, + -86 + ], + [ + 2806, + 1232, + 121, + 47, + -99, + -86 + ] + ], + [ + [ + 2928, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3015, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3102, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3189, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3276, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3363, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3450, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3537, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3624, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3711, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3798, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3885, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 3972, + 1232, + 86, + 66, + -68, + -100 + ], + [ + 0, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 87, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 174, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 261, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 348, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 435, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 522, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 609, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 696, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 783, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 870, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 957, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 1044, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 1131, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 1218, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 1305, + 1299, + 86, + 66, + -68, + -100 + ], + [ + 1392, + 1299, + 86, + 66, + -68, + -100 + ] + ], + [ + [ + 1479, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1520, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1561, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1602, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1643, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1684, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1725, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1766, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1807, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1848, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1889, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1930, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 1971, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2012, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2053, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2094, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2135, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2176, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2217, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2258, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2299, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2340, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2381, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2422, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2463, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2504, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2545, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2586, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2627, + 1299, + 40, + 70, + -25, + -109 + ], + [ + 2668, + 1299, + 40, + 70, + -25, + -109 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/poisonnova.png b/public/missiles/poisonnova.png new file mode 100644 index 0000000..3b30925 Binary files /dev/null and b/public/missiles/poisonnova.png differ diff --git a/public/missiles/teeth.json b/public/missiles/teeth.json new file mode 100644 index 0000000..07f6ab8 --- /dev/null +++ b/public/missiles/teeth.json @@ -0,0 +1,7755 @@ +{ + "name": "teeth", + "celFile": "teethMissile", + "width": 2048, + "height": 1242, + "directions": 32, + "framesPerDirection": 30, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 63, + 38, + -15, + -51 + ], + [ + 64, + 0, + 63, + 38, + -15, + -51 + ], + [ + 128, + 0, + 63, + 38, + -15, + -51 + ], + [ + 192, + 0, + 63, + 38, + -15, + -51 + ], + [ + 256, + 0, + 63, + 38, + -15, + -51 + ], + [ + 320, + 0, + 63, + 38, + -15, + -51 + ], + [ + 384, + 0, + 63, + 38, + -15, + -51 + ], + [ + 448, + 0, + 63, + 38, + -15, + -51 + ], + [ + 512, + 0, + 63, + 38, + -15, + -51 + ], + [ + 576, + 0, + 63, + 38, + -15, + -51 + ], + [ + 640, + 0, + 63, + 38, + -15, + -51 + ], + [ + 704, + 0, + 63, + 38, + -15, + -51 + ], + [ + 768, + 0, + 63, + 38, + -15, + -51 + ], + [ + 832, + 0, + 63, + 38, + -15, + -51 + ], + [ + 896, + 0, + 63, + 38, + -15, + -51 + ], + [ + 960, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1024, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1088, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1152, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1216, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1280, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1344, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1408, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1472, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1536, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1600, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1664, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1728, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1792, + 0, + 63, + 38, + -15, + -51 + ], + [ + 1856, + 0, + 63, + 38, + -15, + -51 + ] + ], + [ + [ + 1920, + 0, + 57, + 43, + -14, + -42 + ], + [ + 1978, + 0, + 57, + 43, + -14, + -42 + ], + [ + 0, + 44, + 57, + 43, + -14, + -42 + ], + [ + 58, + 44, + 57, + 43, + -14, + -42 + ], + [ + 116, + 44, + 57, + 43, + -14, + -42 + ], + [ + 174, + 44, + 57, + 43, + -14, + -42 + ], + [ + 232, + 44, + 57, + 43, + -14, + -42 + ], + [ + 290, + 44, + 57, + 43, + -14, + -42 + ], + [ + 348, + 44, + 57, + 43, + -14, + -42 + ], + [ + 406, + 44, + 57, + 43, + -14, + -42 + ], + [ + 464, + 44, + 57, + 43, + -14, + -42 + ], + [ + 522, + 44, + 57, + 43, + -14, + -42 + ], + [ + 580, + 44, + 57, + 43, + -14, + -42 + ], + [ + 638, + 44, + 57, + 43, + -14, + -42 + ], + [ + 696, + 44, + 57, + 43, + -14, + -42 + ], + [ + 754, + 44, + 57, + 43, + -14, + -42 + ], + [ + 812, + 44, + 57, + 43, + -14, + -42 + ], + [ + 870, + 44, + 57, + 43, + -14, + -42 + ], + [ + 928, + 44, + 57, + 43, + -14, + -42 + ], + [ + 986, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1044, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1102, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1160, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1218, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1276, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1334, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1392, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1450, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1508, + 44, + 57, + 43, + -14, + -42 + ], + [ + 1566, + 44, + 57, + 43, + -14, + -42 + ] + ], + [ + [ + 1624, + 44, + 58, + 44, + -44, + -35 + ], + [ + 1683, + 44, + 58, + 44, + -44, + -35 + ], + [ + 1742, + 44, + 58, + 44, + -44, + -35 + ], + [ + 1801, + 44, + 58, + 44, + -44, + -35 + ], + [ + 1860, + 44, + 58, + 44, + -44, + -35 + ], + [ + 1919, + 44, + 58, + 44, + -44, + -35 + ], + [ + 1978, + 44, + 58, + 44, + -44, + -35 + ], + [ + 0, + 89, + 58, + 44, + -44, + -35 + ], + [ + 59, + 89, + 58, + 44, + -44, + -35 + ], + [ + 118, + 89, + 58, + 44, + -44, + -35 + ], + [ + 177, + 89, + 58, + 44, + -44, + -35 + ], + [ + 236, + 89, + 58, + 44, + -44, + -35 + ], + [ + 295, + 89, + 58, + 44, + -44, + -35 + ], + [ + 354, + 89, + 58, + 44, + -44, + -35 + ], + [ + 413, + 89, + 58, + 44, + -44, + -35 + ], + [ + 472, + 89, + 58, + 44, + -44, + -35 + ], + [ + 531, + 89, + 58, + 44, + -44, + -35 + ], + [ + 590, + 89, + 58, + 44, + -44, + -35 + ], + [ + 649, + 89, + 58, + 44, + -44, + -35 + ], + [ + 708, + 89, + 58, + 44, + -44, + -35 + ], + [ + 767, + 89, + 58, + 44, + -44, + -35 + ], + [ + 826, + 89, + 58, + 44, + -44, + -35 + ], + [ + 885, + 89, + 58, + 44, + -44, + -35 + ], + [ + 944, + 89, + 58, + 44, + -44, + -35 + ], + [ + 1003, + 89, + 58, + 44, + -44, + -35 + ], + [ + 1062, + 89, + 58, + 44, + -44, + -35 + ], + [ + 1121, + 89, + 58, + 44, + -44, + -35 + ], + [ + 1180, + 89, + 58, + 44, + -44, + -35 + ], + [ + 1239, + 89, + 58, + 44, + -44, + -35 + ], + [ + 1298, + 89, + 58, + 44, + -44, + -35 + ] + ], + [ + [ + 1357, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1412, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1467, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1522, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1577, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1632, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1687, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1742, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1797, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1852, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1907, + 89, + 54, + 44, + -40, + -56 + ], + [ + 1962, + 89, + 54, + 44, + -40, + -56 + ], + [ + 0, + 134, + 54, + 44, + -40, + -56 + ], + [ + 55, + 134, + 54, + 44, + -40, + -56 + ], + [ + 110, + 134, + 54, + 44, + -40, + -56 + ], + [ + 165, + 134, + 54, + 44, + -40, + -56 + ], + [ + 220, + 134, + 54, + 44, + -40, + -56 + ], + [ + 275, + 134, + 54, + 44, + -40, + -56 + ], + [ + 330, + 134, + 54, + 44, + -40, + -56 + ], + [ + 385, + 134, + 54, + 44, + -40, + -56 + ], + [ + 440, + 134, + 54, + 44, + -40, + -56 + ], + [ + 495, + 134, + 54, + 44, + -40, + -56 + ], + [ + 550, + 134, + 54, + 44, + -40, + -56 + ], + [ + 605, + 134, + 54, + 44, + -40, + -56 + ], + [ + 660, + 134, + 54, + 44, + -40, + -56 + ], + [ + 715, + 134, + 54, + 44, + -40, + -56 + ], + [ + 770, + 134, + 54, + 44, + -40, + -56 + ], + [ + 825, + 134, + 54, + 44, + -40, + -56 + ], + [ + 880, + 134, + 54, + 44, + -40, + -56 + ], + [ + 935, + 134, + 54, + 44, + -40, + -56 + ] + ], + [ + [ + 990, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1026, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1062, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1098, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1134, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1170, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1206, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1242, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1278, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1314, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1350, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1386, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1422, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1458, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1494, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1530, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1566, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1602, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1638, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1674, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1710, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1746, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1782, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1818, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1854, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1890, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1926, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1962, + 134, + 35, + 53, + -19, + -63 + ], + [ + 1998, + 134, + 35, + 53, + -19, + -63 + ], + [ + 0, + 188, + 35, + 53, + -19, + -63 + ] + ], + [ + [ + 36, + 188, + 66, + 32, + -10, + -42 + ], + [ + 103, + 188, + 66, + 32, + -10, + -42 + ], + [ + 170, + 188, + 66, + 32, + -10, + -42 + ], + [ + 237, + 188, + 66, + 32, + -10, + -42 + ], + [ + 304, + 188, + 66, + 32, + -10, + -42 + ], + [ + 371, + 188, + 66, + 32, + -10, + -42 + ], + [ + 438, + 188, + 66, + 32, + -10, + -42 + ], + [ + 505, + 188, + 66, + 32, + -10, + -42 + ], + [ + 572, + 188, + 66, + 32, + -10, + -42 + ], + [ + 639, + 188, + 66, + 32, + -10, + -42 + ], + [ + 706, + 188, + 66, + 32, + -10, + -42 + ], + [ + 773, + 188, + 66, + 32, + -10, + -42 + ], + [ + 840, + 188, + 66, + 32, + -10, + -42 + ], + [ + 907, + 188, + 66, + 32, + -10, + -42 + ], + [ + 974, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1041, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1108, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1175, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1242, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1309, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1376, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1443, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1510, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1577, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1644, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1711, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1778, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1845, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1912, + 188, + 66, + 32, + -10, + -42 + ], + [ + 1979, + 188, + 66, + 32, + -10, + -42 + ] + ], + [ + [ + 0, + 242, + 26, + 53, + -14, + -40 + ], + [ + 27, + 242, + 26, + 53, + -14, + -40 + ], + [ + 54, + 242, + 26, + 53, + -14, + -40 + ], + [ + 81, + 242, + 26, + 53, + -14, + -40 + ], + [ + 108, + 242, + 26, + 53, + -14, + -40 + ], + [ + 135, + 242, + 26, + 53, + -14, + -40 + ], + [ + 162, + 242, + 26, + 53, + -14, + -40 + ], + [ + 189, + 242, + 26, + 53, + -14, + -40 + ], + [ + 216, + 242, + 26, + 53, + -14, + -40 + ], + [ + 243, + 242, + 26, + 53, + -14, + -40 + ], + [ + 270, + 242, + 26, + 53, + -14, + -40 + ], + [ + 297, + 242, + 26, + 53, + -14, + -40 + ], + [ + 324, + 242, + 26, + 53, + -14, + -40 + ], + [ + 351, + 242, + 26, + 53, + -14, + -40 + ], + [ + 378, + 242, + 26, + 53, + -14, + -40 + ], + [ + 405, + 242, + 26, + 53, + -14, + -40 + ], + [ + 432, + 242, + 26, + 53, + -14, + -40 + ], + [ + 459, + 242, + 26, + 53, + -14, + -40 + ], + [ + 486, + 242, + 26, + 53, + -14, + -40 + ], + [ + 513, + 242, + 26, + 53, + -14, + -40 + ], + [ + 540, + 242, + 26, + 53, + -14, + -40 + ], + [ + 567, + 242, + 26, + 53, + -14, + -40 + ], + [ + 594, + 242, + 26, + 53, + -14, + -40 + ], + [ + 621, + 242, + 26, + 53, + -14, + -40 + ], + [ + 648, + 242, + 26, + 53, + -14, + -40 + ], + [ + 675, + 242, + 26, + 53, + -14, + -40 + ], + [ + 702, + 242, + 26, + 53, + -14, + -40 + ], + [ + 729, + 242, + 26, + 53, + -14, + -40 + ], + [ + 756, + 242, + 26, + 53, + -14, + -40 + ], + [ + 783, + 242, + 26, + 53, + -14, + -40 + ] + ], + [ + [ + 810, + 242, + 68, + 30, + -56, + -40 + ], + [ + 879, + 242, + 68, + 30, + -56, + -40 + ], + [ + 948, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1017, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1086, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1155, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1224, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1293, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1362, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1431, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1500, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1569, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1638, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1707, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1776, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1845, + 242, + 68, + 30, + -56, + -40 + ], + [ + 1914, + 242, + 68, + 30, + -56, + -40 + ], + [ + 0, + 296, + 68, + 30, + -56, + -40 + ], + [ + 69, + 296, + 68, + 30, + -56, + -40 + ], + [ + 138, + 296, + 68, + 30, + -56, + -40 + ], + [ + 207, + 296, + 68, + 30, + -56, + -40 + ], + [ + 276, + 296, + 68, + 30, + -56, + -40 + ], + [ + 345, + 296, + 68, + 30, + -56, + -40 + ], + [ + 414, + 296, + 68, + 30, + -56, + -40 + ], + [ + 483, + 296, + 68, + 30, + -56, + -40 + ], + [ + 552, + 296, + 68, + 30, + -56, + -40 + ], + [ + 621, + 296, + 68, + 30, + -56, + -40 + ], + [ + 690, + 296, + 68, + 30, + -56, + -40 + ], + [ + 759, + 296, + 68, + 30, + -56, + -40 + ], + [ + 828, + 296, + 68, + 30, + -56, + -40 + ] + ], + [ + [ + 897, + 296, + 38, + 49, + -9, + -63 + ], + [ + 936, + 296, + 38, + 49, + -9, + -63 + ], + [ + 975, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1014, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1053, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1092, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1131, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1170, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1209, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1248, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1287, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1326, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1365, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1404, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1443, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1482, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1521, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1560, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1599, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1638, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1677, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1716, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1755, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1794, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1833, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1872, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1911, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1950, + 296, + 38, + 49, + -9, + -63 + ], + [ + 1989, + 296, + 38, + 49, + -9, + -63 + ], + [ + 0, + 346, + 38, + 49, + -9, + -63 + ] + ], + [ + [ + 39, + 346, + 66, + 30, + -12, + -42 + ], + [ + 106, + 346, + 66, + 30, + -12, + -42 + ], + [ + 173, + 346, + 66, + 30, + -12, + -42 + ], + [ + 240, + 346, + 66, + 30, + -12, + -42 + ], + [ + 307, + 346, + 66, + 30, + -12, + -42 + ], + [ + 374, + 346, + 66, + 30, + -12, + -42 + ], + [ + 441, + 346, + 66, + 30, + -12, + -42 + ], + [ + 508, + 346, + 66, + 30, + -12, + -42 + ], + [ + 575, + 346, + 66, + 30, + -12, + -42 + ], + [ + 642, + 346, + 66, + 30, + -12, + -42 + ], + [ + 709, + 346, + 66, + 30, + -12, + -42 + ], + [ + 776, + 346, + 66, + 30, + -12, + -42 + ], + [ + 843, + 346, + 66, + 30, + -12, + -42 + ], + [ + 910, + 346, + 66, + 30, + -12, + -42 + ], + [ + 977, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1044, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1111, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1178, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1245, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1312, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1379, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1446, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1513, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1580, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1647, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1714, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1781, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1848, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1915, + 346, + 66, + 30, + -12, + -42 + ], + [ + 1982, + 346, + 66, + 30, + -12, + -42 + ] + ], + [ + [ + 0, + 396, + 66, + 34, + -13, + -40 + ], + [ + 67, + 396, + 66, + 34, + -13, + -40 + ], + [ + 134, + 396, + 66, + 34, + -13, + -40 + ], + [ + 201, + 396, + 66, + 34, + -13, + -40 + ], + [ + 268, + 396, + 66, + 34, + -13, + -40 + ], + [ + 335, + 396, + 66, + 34, + -13, + -40 + ], + [ + 402, + 396, + 66, + 34, + -13, + -40 + ], + [ + 469, + 396, + 66, + 34, + -13, + -40 + ], + [ + 536, + 396, + 66, + 34, + -13, + -40 + ], + [ + 603, + 396, + 66, + 34, + -13, + -40 + ], + [ + 670, + 396, + 66, + 34, + -13, + -40 + ], + [ + 737, + 396, + 66, + 34, + -13, + -40 + ], + [ + 804, + 396, + 66, + 34, + -13, + -40 + ], + [ + 871, + 396, + 66, + 34, + -13, + -40 + ], + [ + 938, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1005, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1072, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1139, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1206, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1273, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1340, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1407, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1474, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1541, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1608, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1675, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1742, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1809, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1876, + 396, + 66, + 34, + -13, + -40 + ], + [ + 1943, + 396, + 66, + 34, + -13, + -40 + ] + ], + [ + [ + 0, + 431, + 45, + 47, + -15, + -42 + ], + [ + 46, + 431, + 45, + 47, + -15, + -42 + ], + [ + 92, + 431, + 45, + 47, + -15, + -42 + ], + [ + 138, + 431, + 45, + 47, + -15, + -42 + ], + [ + 184, + 431, + 45, + 47, + -15, + -42 + ], + [ + 230, + 431, + 45, + 47, + -15, + -42 + ], + [ + 276, + 431, + 45, + 47, + -15, + -42 + ], + [ + 322, + 431, + 45, + 47, + -15, + -42 + ], + [ + 368, + 431, + 45, + 47, + -15, + -42 + ], + [ + 414, + 431, + 45, + 47, + -15, + -42 + ], + [ + 460, + 431, + 45, + 47, + -15, + -42 + ], + [ + 506, + 431, + 45, + 47, + -15, + -42 + ], + [ + 552, + 431, + 45, + 47, + -15, + -42 + ], + [ + 598, + 431, + 45, + 47, + -15, + -42 + ], + [ + 644, + 431, + 45, + 47, + -15, + -42 + ], + [ + 690, + 431, + 45, + 47, + -15, + -42 + ], + [ + 736, + 431, + 45, + 47, + -15, + -42 + ], + [ + 782, + 431, + 45, + 47, + -15, + -42 + ], + [ + 828, + 431, + 45, + 47, + -15, + -42 + ], + [ + 874, + 431, + 45, + 47, + -15, + -42 + ], + [ + 920, + 431, + 45, + 47, + -15, + -42 + ], + [ + 966, + 431, + 45, + 47, + -15, + -42 + ], + [ + 1012, + 431, + 45, + 47, + -15, + -42 + ], + [ + 1058, + 431, + 45, + 47, + -15, + -42 + ], + [ + 1104, + 431, + 45, + 47, + -15, + -42 + ], + [ + 1150, + 431, + 45, + 47, + -15, + -42 + ], + [ + 1196, + 431, + 45, + 47, + -15, + -42 + ], + [ + 1242, + 431, + 45, + 47, + -15, + -42 + ], + [ + 1288, + 431, + 45, + 47, + -15, + -42 + ], + [ + 1334, + 431, + 45, + 47, + -15, + -42 + ] + ], + [ + [ + 1380, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1422, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1464, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1506, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1548, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1590, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1632, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1674, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1716, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1758, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1800, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1842, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1884, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1926, + 431, + 41, + 54, + -29, + -44 + ], + [ + 1968, + 431, + 41, + 54, + -29, + -44 + ], + [ + 0, + 486, + 41, + 54, + -29, + -44 + ], + [ + 42, + 486, + 41, + 54, + -29, + -44 + ], + [ + 84, + 486, + 41, + 54, + -29, + -44 + ], + [ + 126, + 486, + 41, + 54, + -29, + -44 + ], + [ + 168, + 486, + 41, + 54, + -29, + -44 + ], + [ + 210, + 486, + 41, + 54, + -29, + -44 + ], + [ + 252, + 486, + 41, + 54, + -29, + -44 + ], + [ + 294, + 486, + 41, + 54, + -29, + -44 + ], + [ + 336, + 486, + 41, + 54, + -29, + -44 + ], + [ + 378, + 486, + 41, + 54, + -29, + -44 + ], + [ + 420, + 486, + 41, + 54, + -29, + -44 + ], + [ + 462, + 486, + 41, + 54, + -29, + -44 + ], + [ + 504, + 486, + 41, + 54, + -29, + -44 + ], + [ + 546, + 486, + 41, + 54, + -29, + -44 + ], + [ + 588, + 486, + 41, + 54, + -29, + -44 + ] + ], + [ + [ + 630, + 486, + 67, + 34, + -53, + -38 + ], + [ + 698, + 486, + 67, + 34, + -53, + -38 + ], + [ + 766, + 486, + 67, + 34, + -53, + -38 + ], + [ + 834, + 486, + 67, + 34, + -53, + -38 + ], + [ + 902, + 486, + 67, + 34, + -53, + -38 + ], + [ + 970, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1038, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1106, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1174, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1242, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1310, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1378, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1446, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1514, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1582, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1650, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1718, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1786, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1854, + 486, + 67, + 34, + -53, + -38 + ], + [ + 1922, + 486, + 67, + 34, + -53, + -38 + ], + [ + 0, + 541, + 67, + 34, + -53, + -38 + ], + [ + 68, + 541, + 67, + 34, + -53, + -38 + ], + [ + 136, + 541, + 67, + 34, + -53, + -38 + ], + [ + 204, + 541, + 67, + 34, + -53, + -38 + ], + [ + 272, + 541, + 67, + 34, + -53, + -38 + ], + [ + 340, + 541, + 67, + 34, + -53, + -38 + ], + [ + 408, + 541, + 67, + 34, + -53, + -38 + ], + [ + 476, + 541, + 67, + 34, + -53, + -38 + ], + [ + 544, + 541, + 67, + 34, + -53, + -38 + ], + [ + 612, + 541, + 67, + 34, + -53, + -38 + ] + ], + [ + [ + 680, + 541, + 65, + 42, + -53, + -47 + ], + [ + 746, + 541, + 65, + 42, + -53, + -47 + ], + [ + 812, + 541, + 65, + 42, + -53, + -47 + ], + [ + 878, + 541, + 65, + 42, + -53, + -47 + ], + [ + 944, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1010, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1076, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1142, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1208, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1274, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1340, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1406, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1472, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1538, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1604, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1670, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1736, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1802, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1868, + 541, + 65, + 42, + -53, + -47 + ], + [ + 1934, + 541, + 65, + 42, + -53, + -47 + ], + [ + 0, + 584, + 65, + 42, + -53, + -47 + ], + [ + 66, + 584, + 65, + 42, + -53, + -47 + ], + [ + 132, + 584, + 65, + 42, + -53, + -47 + ], + [ + 198, + 584, + 65, + 42, + -53, + -47 + ], + [ + 264, + 584, + 65, + 42, + -53, + -47 + ], + [ + 330, + 584, + 65, + 42, + -53, + -47 + ], + [ + 396, + 584, + 65, + 42, + -53, + -47 + ], + [ + 462, + 584, + 65, + 42, + -53, + -47 + ], + [ + 528, + 584, + 65, + 42, + -53, + -47 + ], + [ + 594, + 584, + 65, + 42, + -53, + -47 + ] + ], + [ + [ + 660, + 584, + 44, + 53, + -30, + -57 + ], + [ + 705, + 584, + 44, + 53, + -30, + -57 + ], + [ + 750, + 584, + 44, + 53, + -30, + -57 + ], + [ + 795, + 584, + 44, + 53, + -30, + -57 + ], + [ + 840, + 584, + 44, + 53, + -30, + -57 + ], + [ + 885, + 584, + 44, + 53, + -30, + -57 + ], + [ + 930, + 584, + 44, + 53, + -30, + -57 + ], + [ + 975, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1020, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1065, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1110, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1155, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1200, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1245, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1290, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1335, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1380, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1425, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1470, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1515, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1560, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1605, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1650, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1695, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1740, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1785, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1830, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1875, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1920, + 584, + 44, + 53, + -30, + -57 + ], + [ + 1965, + 584, + 44, + 53, + -30, + -57 + ] + ], + [ + [ + 2010, + 584, + 32, + 50, + -14, + -60 + ], + [ + 0, + 638, + 32, + 50, + -14, + -60 + ], + [ + 33, + 638, + 32, + 50, + -14, + -60 + ], + [ + 66, + 638, + 32, + 50, + -14, + -60 + ], + [ + 99, + 638, + 32, + 50, + -14, + -60 + ], + [ + 132, + 638, + 32, + 50, + -14, + -60 + ], + [ + 165, + 638, + 32, + 50, + -14, + -60 + ], + [ + 198, + 638, + 32, + 50, + -14, + -60 + ], + [ + 231, + 638, + 32, + 50, + -14, + -60 + ], + [ + 264, + 638, + 32, + 50, + -14, + -60 + ], + [ + 297, + 638, + 32, + 50, + -14, + -60 + ], + [ + 330, + 638, + 32, + 50, + -14, + -60 + ], + [ + 363, + 638, + 32, + 50, + -14, + -60 + ], + [ + 396, + 638, + 32, + 50, + -14, + -60 + ], + [ + 429, + 638, + 32, + 50, + -14, + -60 + ], + [ + 462, + 638, + 32, + 50, + -14, + -60 + ], + [ + 495, + 638, + 32, + 50, + -14, + -60 + ], + [ + 528, + 638, + 32, + 50, + -14, + -60 + ], + [ + 561, + 638, + 32, + 50, + -14, + -60 + ], + [ + 594, + 638, + 32, + 50, + -14, + -60 + ], + [ + 627, + 638, + 32, + 50, + -14, + -60 + ], + [ + 660, + 638, + 32, + 50, + -14, + -60 + ], + [ + 693, + 638, + 32, + 50, + -14, + -60 + ], + [ + 726, + 638, + 32, + 50, + -14, + -60 + ], + [ + 759, + 638, + 32, + 50, + -14, + -60 + ], + [ + 792, + 638, + 32, + 50, + -14, + -60 + ], + [ + 825, + 638, + 32, + 50, + -14, + -60 + ], + [ + 858, + 638, + 32, + 50, + -14, + -60 + ], + [ + 891, + 638, + 32, + 50, + -14, + -60 + ], + [ + 924, + 638, + 32, + 50, + -14, + -60 + ] + ], + [ + [ + 957, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1016, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1075, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1134, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1193, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1252, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1311, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1370, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1429, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1488, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1547, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1606, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1665, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1724, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1783, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1842, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1901, + 638, + 58, + 41, + -16, + -52 + ], + [ + 1960, + 638, + 58, + 41, + -16, + -52 + ], + [ + 0, + 689, + 58, + 41, + -16, + -52 + ], + [ + 59, + 689, + 58, + 41, + -16, + -52 + ], + [ + 118, + 689, + 58, + 41, + -16, + -52 + ], + [ + 177, + 689, + 58, + 41, + -16, + -52 + ], + [ + 236, + 689, + 58, + 41, + -16, + -52 + ], + [ + 295, + 689, + 58, + 41, + -16, + -52 + ], + [ + 354, + 689, + 58, + 41, + -16, + -52 + ], + [ + 413, + 689, + 58, + 41, + -16, + -52 + ], + [ + 472, + 689, + 58, + 41, + -16, + -52 + ], + [ + 531, + 689, + 58, + 41, + -16, + -52 + ], + [ + 590, + 689, + 58, + 41, + -16, + -52 + ], + [ + 649, + 689, + 58, + 41, + -16, + -52 + ] + ], + [ + [ + 708, + 689, + 63, + 37, + -15, + -49 + ], + [ + 772, + 689, + 63, + 37, + -15, + -49 + ], + [ + 836, + 689, + 63, + 37, + -15, + -49 + ], + [ + 900, + 689, + 63, + 37, + -15, + -49 + ], + [ + 964, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1028, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1092, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1156, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1220, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1284, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1348, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1412, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1476, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1540, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1604, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1668, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1732, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1796, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1860, + 689, + 63, + 37, + -15, + -49 + ], + [ + 1924, + 689, + 63, + 37, + -15, + -49 + ], + [ + 0, + 731, + 63, + 37, + -15, + -49 + ], + [ + 64, + 731, + 63, + 37, + -15, + -49 + ], + [ + 128, + 731, + 63, + 37, + -15, + -49 + ], + [ + 192, + 731, + 63, + 37, + -15, + -49 + ], + [ + 256, + 731, + 63, + 37, + -15, + -49 + ], + [ + 320, + 731, + 63, + 37, + -15, + -49 + ], + [ + 384, + 731, + 63, + 37, + -15, + -49 + ], + [ + 448, + 731, + 63, + 37, + -15, + -49 + ], + [ + 512, + 731, + 63, + 37, + -15, + -49 + ], + [ + 576, + 731, + 63, + 37, + -15, + -49 + ] + ], + [ + [ + 640, + 731, + 68, + 35, + -14, + -44 + ], + [ + 709, + 731, + 68, + 35, + -14, + -44 + ], + [ + 778, + 731, + 68, + 35, + -14, + -44 + ], + [ + 847, + 731, + 68, + 35, + -14, + -44 + ], + [ + 916, + 731, + 68, + 35, + -14, + -44 + ], + [ + 985, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1054, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1123, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1192, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1261, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1330, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1399, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1468, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1537, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1606, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1675, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1744, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1813, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1882, + 731, + 68, + 35, + -14, + -44 + ], + [ + 1951, + 731, + 68, + 35, + -14, + -44 + ], + [ + 0, + 769, + 68, + 35, + -14, + -44 + ], + [ + 69, + 769, + 68, + 35, + -14, + -44 + ], + [ + 138, + 769, + 68, + 35, + -14, + -44 + ], + [ + 207, + 769, + 68, + 35, + -14, + -44 + ], + [ + 276, + 769, + 68, + 35, + -14, + -44 + ], + [ + 345, + 769, + 68, + 35, + -14, + -44 + ], + [ + 414, + 769, + 68, + 35, + -14, + -44 + ], + [ + 483, + 769, + 68, + 35, + -14, + -44 + ], + [ + 552, + 769, + 68, + 35, + -14, + -44 + ], + [ + 621, + 769, + 68, + 35, + -14, + -44 + ] + ], + [ + [ + 690, + 769, + 66, + 27, + -11, + -36 + ], + [ + 757, + 769, + 66, + 27, + -11, + -36 + ], + [ + 824, + 769, + 66, + 27, + -11, + -36 + ], + [ + 891, + 769, + 66, + 27, + -11, + -36 + ], + [ + 958, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1025, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1092, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1159, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1226, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1293, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1360, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1427, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1494, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1561, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1628, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1695, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1762, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1829, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1896, + 769, + 66, + 27, + -11, + -36 + ], + [ + 1963, + 769, + 66, + 27, + -11, + -36 + ], + [ + 0, + 805, + 66, + 27, + -11, + -36 + ], + [ + 67, + 805, + 66, + 27, + -11, + -36 + ], + [ + 134, + 805, + 66, + 27, + -11, + -36 + ], + [ + 201, + 805, + 66, + 27, + -11, + -36 + ], + [ + 268, + 805, + 66, + 27, + -11, + -36 + ], + [ + 335, + 805, + 66, + 27, + -11, + -36 + ], + [ + 402, + 805, + 66, + 27, + -11, + -36 + ], + [ + 469, + 805, + 66, + 27, + -11, + -36 + ], + [ + 536, + 805, + 66, + 27, + -11, + -36 + ], + [ + 603, + 805, + 66, + 27, + -11, + -36 + ] + ], + [ + [ + 670, + 805, + 64, + 35, + -14, + -42 + ], + [ + 735, + 805, + 64, + 35, + -14, + -42 + ], + [ + 800, + 805, + 64, + 35, + -14, + -42 + ], + [ + 865, + 805, + 64, + 35, + -14, + -42 + ], + [ + 930, + 805, + 64, + 35, + -14, + -42 + ], + [ + 995, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1060, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1125, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1190, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1255, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1320, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1385, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1450, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1515, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1580, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1645, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1710, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1775, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1840, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1905, + 805, + 64, + 35, + -14, + -42 + ], + [ + 1970, + 805, + 64, + 35, + -14, + -42 + ], + [ + 0, + 841, + 64, + 35, + -14, + -42 + ], + [ + 65, + 841, + 64, + 35, + -14, + -42 + ], + [ + 130, + 841, + 64, + 35, + -14, + -42 + ], + [ + 195, + 841, + 64, + 35, + -14, + -42 + ], + [ + 260, + 841, + 64, + 35, + -14, + -42 + ], + [ + 325, + 841, + 64, + 35, + -14, + -42 + ], + [ + 390, + 841, + 64, + 35, + -14, + -42 + ], + [ + 455, + 841, + 64, + 35, + -14, + -42 + ], + [ + 520, + 841, + 64, + 35, + -14, + -42 + ] + ], + [ + [ + 585, + 841, + 49, + 48, + -16, + -40 + ], + [ + 635, + 841, + 49, + 48, + -16, + -40 + ], + [ + 685, + 841, + 49, + 48, + -16, + -40 + ], + [ + 735, + 841, + 49, + 48, + -16, + -40 + ], + [ + 785, + 841, + 49, + 48, + -16, + -40 + ], + [ + 835, + 841, + 49, + 48, + -16, + -40 + ], + [ + 885, + 841, + 49, + 48, + -16, + -40 + ], + [ + 935, + 841, + 49, + 48, + -16, + -40 + ], + [ + 985, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1035, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1085, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1135, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1185, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1235, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1285, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1335, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1385, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1435, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1485, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1535, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1585, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1635, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1685, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1735, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1785, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1835, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1885, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1935, + 841, + 49, + 48, + -16, + -40 + ], + [ + 1985, + 841, + 49, + 48, + -16, + -40 + ], + [ + 0, + 890, + 49, + 48, + -16, + -40 + ] + ], + [ + [ + 50, + 890, + 35, + 46, + -13, + -42 + ], + [ + 86, + 890, + 35, + 46, + -13, + -42 + ], + [ + 122, + 890, + 35, + 46, + -13, + -42 + ], + [ + 158, + 890, + 35, + 46, + -13, + -42 + ], + [ + 194, + 890, + 35, + 46, + -13, + -42 + ], + [ + 230, + 890, + 35, + 46, + -13, + -42 + ], + [ + 266, + 890, + 35, + 46, + -13, + -42 + ], + [ + 302, + 890, + 35, + 46, + -13, + -42 + ], + [ + 338, + 890, + 35, + 46, + -13, + -42 + ], + [ + 374, + 890, + 35, + 46, + -13, + -42 + ], + [ + 410, + 890, + 35, + 46, + -13, + -42 + ], + [ + 446, + 890, + 35, + 46, + -13, + -42 + ], + [ + 482, + 890, + 35, + 46, + -13, + -42 + ], + [ + 518, + 890, + 35, + 46, + -13, + -42 + ], + [ + 554, + 890, + 35, + 46, + -13, + -42 + ], + [ + 590, + 890, + 35, + 46, + -13, + -42 + ], + [ + 626, + 890, + 35, + 46, + -13, + -42 + ], + [ + 662, + 890, + 35, + 46, + -13, + -42 + ], + [ + 698, + 890, + 35, + 46, + -13, + -42 + ], + [ + 734, + 890, + 35, + 46, + -13, + -42 + ], + [ + 770, + 890, + 35, + 46, + -13, + -42 + ], + [ + 806, + 890, + 35, + 46, + -13, + -42 + ], + [ + 842, + 890, + 35, + 46, + -13, + -42 + ], + [ + 878, + 890, + 35, + 46, + -13, + -42 + ], + [ + 914, + 890, + 35, + 46, + -13, + -42 + ], + [ + 950, + 890, + 35, + 46, + -13, + -42 + ], + [ + 986, + 890, + 35, + 46, + -13, + -42 + ], + [ + 1022, + 890, + 35, + 46, + -13, + -42 + ], + [ + 1058, + 890, + 35, + 46, + -13, + -42 + ], + [ + 1094, + 890, + 35, + 46, + -13, + -42 + ] + ], + [ + [ + 1130, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1163, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1196, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1229, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1262, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1295, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1328, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1361, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1394, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1427, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1460, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1493, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1526, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1559, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1592, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1625, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1658, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1691, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1724, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1757, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1790, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1823, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1856, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1889, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1922, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1955, + 890, + 32, + 48, + -22, + -39 + ], + [ + 1988, + 890, + 32, + 48, + -22, + -39 + ], + [ + 0, + 939, + 32, + 48, + -22, + -39 + ], + [ + 33, + 939, + 32, + 48, + -22, + -39 + ], + [ + 66, + 939, + 32, + 48, + -22, + -39 + ] + ], + [ + [ + 99, + 939, + 59, + 47, + -41, + -40 + ], + [ + 159, + 939, + 59, + 47, + -41, + -40 + ], + [ + 219, + 939, + 59, + 47, + -41, + -40 + ], + [ + 279, + 939, + 59, + 47, + -41, + -40 + ], + [ + 339, + 939, + 59, + 47, + -41, + -40 + ], + [ + 399, + 939, + 59, + 47, + -41, + -40 + ], + [ + 459, + 939, + 59, + 47, + -41, + -40 + ], + [ + 519, + 939, + 59, + 47, + -41, + -40 + ], + [ + 579, + 939, + 59, + 47, + -41, + -40 + ], + [ + 639, + 939, + 59, + 47, + -41, + -40 + ], + [ + 699, + 939, + 59, + 47, + -41, + -40 + ], + [ + 759, + 939, + 59, + 47, + -41, + -40 + ], + [ + 819, + 939, + 59, + 47, + -41, + -40 + ], + [ + 879, + 939, + 59, + 47, + -41, + -40 + ], + [ + 939, + 939, + 59, + 47, + -41, + -40 + ], + [ + 999, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1059, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1119, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1179, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1239, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1299, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1359, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1419, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1479, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1539, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1599, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1659, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1719, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1779, + 939, + 59, + 47, + -41, + -40 + ], + [ + 1839, + 939, + 59, + 47, + -41, + -40 + ] + ], + [ + [ + 1899, + 939, + 66, + 35, + -51, + -38 + ], + [ + 1966, + 939, + 66, + 35, + -51, + -38 + ], + [ + 0, + 988, + 66, + 35, + -51, + -38 + ], + [ + 67, + 988, + 66, + 35, + -51, + -38 + ], + [ + 134, + 988, + 66, + 35, + -51, + -38 + ], + [ + 201, + 988, + 66, + 35, + -51, + -38 + ], + [ + 268, + 988, + 66, + 35, + -51, + -38 + ], + [ + 335, + 988, + 66, + 35, + -51, + -38 + ], + [ + 402, + 988, + 66, + 35, + -51, + -38 + ], + [ + 469, + 988, + 66, + 35, + -51, + -38 + ], + [ + 536, + 988, + 66, + 35, + -51, + -38 + ], + [ + 603, + 988, + 66, + 35, + -51, + -38 + ], + [ + 670, + 988, + 66, + 35, + -51, + -38 + ], + [ + 737, + 988, + 66, + 35, + -51, + -38 + ], + [ + 804, + 988, + 66, + 35, + -51, + -38 + ], + [ + 871, + 988, + 66, + 35, + -51, + -38 + ], + [ + 938, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1005, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1072, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1139, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1206, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1273, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1340, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1407, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1474, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1541, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1608, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1675, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1742, + 988, + 66, + 35, + -51, + -38 + ], + [ + 1809, + 988, + 66, + 35, + -51, + -38 + ] + ], + [ + [ + 1876, + 988, + 69, + 32, + -56, + -38 + ], + [ + 1946, + 988, + 69, + 32, + -56, + -38 + ], + [ + 0, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 70, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 140, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 210, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 280, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 350, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 420, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 490, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 560, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 630, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 700, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 770, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 840, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 910, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 980, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1050, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1120, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1190, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1260, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1330, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1400, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1470, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1540, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1610, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1680, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1750, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1820, + 1024, + 69, + 32, + -56, + -38 + ], + [ + 1890, + 1024, + 69, + 32, + -56, + -38 + ] + ], + [ + [ + 1960, + 1024, + 67, + 29, + -56, + -38 + ], + [ + 0, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 68, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 136, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 204, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 272, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 340, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 408, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 476, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 544, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 612, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 680, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 748, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 816, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 884, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 952, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1020, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1088, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1156, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1224, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1292, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1360, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1428, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1496, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1564, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1632, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1700, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1768, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1836, + 1057, + 67, + 29, + -56, + -38 + ], + [ + 1904, + 1057, + 67, + 29, + -56, + -38 + ] + ], + [ + [ + 1972, + 1057, + 59, + 38, + -43, + -48 + ], + [ + 0, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 60, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 120, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 180, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 240, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 300, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 360, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 420, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 480, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 540, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 600, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 660, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 720, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 780, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 840, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 900, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 960, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1020, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1080, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1140, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1200, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1260, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1320, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1380, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1440, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1500, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1560, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1620, + 1096, + 59, + 38, + -43, + -48 + ], + [ + 1680, + 1096, + 59, + 38, + -43, + -48 + ] + ], + [ + [ + 1740, + 1096, + 51, + 49, + -32, + -59 + ], + [ + 1792, + 1096, + 51, + 49, + -32, + -59 + ], + [ + 1844, + 1096, + 51, + 49, + -32, + -59 + ], + [ + 1896, + 1096, + 51, + 49, + -32, + -59 + ], + [ + 1948, + 1096, + 51, + 49, + -32, + -59 + ], + [ + 0, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 52, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 104, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 156, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 208, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 260, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 312, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 364, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 416, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 468, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 520, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 572, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 624, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 676, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 728, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 780, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 832, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 884, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 936, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 988, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 1040, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 1092, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 1144, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 1196, + 1146, + 51, + 49, + -32, + -59 + ], + [ + 1248, + 1146, + 51, + 49, + -32, + -59 + ] + ], + [ + [ + 1300, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1337, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1374, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1411, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1448, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1485, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1522, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1559, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1596, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1633, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1670, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1707, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1744, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1781, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1818, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1855, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1892, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1929, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 1966, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 2003, + 1146, + 36, + 46, + -24, + -57 + ], + [ + 0, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 37, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 74, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 111, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 148, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 185, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 222, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 259, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 296, + 1196, + 36, + 46, + -24, + -57 + ], + [ + 333, + 1196, + 36, + 46, + -24, + -57 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/teeth.png b/public/missiles/teeth.png new file mode 100644 index 0000000..3f9fcf1 Binary files /dev/null and b/public/missiles/teeth.png differ diff --git a/public/missiles/teethexplode.json b/public/missiles/teethexplode.json new file mode 100644 index 0000000..7ca04d9 --- /dev/null +++ b/public/missiles/teethexplode.json @@ -0,0 +1,117 @@ +{ + "name": "teethexplode", + "celFile": "teethexplode", + "width": 512, + "height": 427, + "directions": 1, + "framesPerDirection": 13, + "animSpeed": 16, + "groups": [ + [ + [ + 0, + 0, + 105, + 106, + -52, + -100 + ], + [ + 106, + 0, + 105, + 106, + -52, + -100 + ], + [ + 212, + 0, + 105, + 106, + -52, + -100 + ], + [ + 318, + 0, + 105, + 106, + -52, + -100 + ], + [ + 0, + 107, + 105, + 106, + -52, + -100 + ], + [ + 106, + 107, + 105, + 106, + -52, + -100 + ], + [ + 212, + 107, + 105, + 106, + -52, + -100 + ], + [ + 318, + 107, + 105, + 106, + -52, + -100 + ], + [ + 0, + 214, + 105, + 106, + -52, + -100 + ], + [ + 106, + 214, + 105, + 106, + -52, + -100 + ], + [ + 212, + 214, + 105, + 106, + -52, + -100 + ], + [ + 318, + 214, + 105, + 106, + -52, + -100 + ], + [ + 0, + 321, + 105, + 106, + -52, + -100 + ] + ] + ] +} \ No newline at end of file diff --git a/public/missiles/teethexplode.png b/public/missiles/teethexplode.png new file mode 100644 index 0000000..f29601e Binary files /dev/null and b/public/missiles/teethexplode.png differ diff --git a/scripts/pack-missiles.ts b/scripts/pack-missiles.ts index 270c88e..1a71cc5 100644 --- a/scripts/pack-missiles.ts +++ b/scripts/pack-missiles.ts @@ -1,10 +1,13 @@ /** * Offline Missile Asset & Data Baking Script. * - * Extracts authentic Diablo II v1.13c missile DCC sprites from d2data.mpq: - * - Firebolt.dcc (16 directions, 5 frames per direction) - * - Fireball.dcc (16 directions, 5 frames per direction) - * - FireArrowExplode2.dcc (1 direction, 12 frames) + * Extracts authentic Diablo II v1.13c missile DCC sprites from MPQ archives: + * - Fire: Firebolt, Fireball, FireArrowExplode2 + * - Cold: Icebolt, IceBlast, GlacialSpike, IceArrowExplode, FreezeExplodeCenter + * - Lightning: ChargedBolt + * - Necromancer: teethMissile, teethexplode, BoneSpear, BoneSpirit, BoneSpiritExplode, poisonNova + * - Paladin: HolyBoltMissile, blessedhammer + * - Amazon: SafeArrow, FireArrow, IceArrow, Arrow, LightningJavelin * * Bakes them into indexed-color PNG atlases and JSON metadata under: * - public/missiles/ @@ -20,7 +23,7 @@ import { MpqArchive } from '../src/mpq/archive.ts' import { fileSource } from '../src/mpq/file-source.ts' import { decodeDcc } from '../src/formats/dcc.ts' import { decodePl2 } from '../src/formats/pl2.ts' -import { packSheetToPng } from './pack-entity-assets.ts' +import { encodeRgbaPng } from './png.ts' import type { SpriteFrame, SpriteSheet } from '../src/formats/sprite.ts' export interface MissileFrameMeta { @@ -53,18 +56,196 @@ export interface MissileMeta { } const MISSILE_TARGETS = [ + // Fire spells & explosions { name: 'firebolt', celFile: 'Firebolt', animSpeed: 16 }, { name: 'fireball', celFile: 'Fireball', animSpeed: 16 }, { name: 'fireexplode', celFile: 'FireArrowExplode2', animSpeed: 16 }, + + // Ice spells & explosions + { name: 'icebolt', celFile: 'Icebolt', animSpeed: 16 }, + { name: 'iceblast', celFile: 'IceBlast', animSpeed: 16 }, + { name: 'glacialspike', celFile: 'GlacialSpike', animSpeed: 16 }, + { name: 'iceexplode', celFile: 'IceArrowExplode', animSpeed: 16 }, + { name: 'freezeexplode', celFile: 'FreezeExplodeCenter', animSpeed: 16 }, + + // Lightning + { name: 'chargedbolt', celFile: 'ChargedBolt', animSpeed: 16 }, + + // Necromancer + { name: 'teeth', celFile: 'teethMissile', animSpeed: 16 }, + { name: 'teethexplode', celFile: 'teethexplode', animSpeed: 16 }, + { name: 'bonespear', celFile: 'BoneSpear', animSpeed: 16 }, + { name: 'bonespirit', celFile: 'BoneSpirit', animSpeed: 16 }, + { name: 'bonespiritexplode', celFile: 'BoneSpiritExplode', animSpeed: 16 }, + { name: 'poisonnova', celFile: 'poisonNova', animSpeed: 16 }, + + // Paladin + { name: 'holybolt', celFile: 'HolyBoltMissile', animSpeed: 16 }, + { name: 'blessedhammer', celFile: 'blessedhammer', animSpeed: 16 }, + + // Amazon + { name: 'magicarrow', celFile: 'SafeArrow', animSpeed: 16 }, + { name: 'firearrow', celFile: 'FireArrow', animSpeed: 16 }, + { name: 'icearrow', celFile: 'IceArrow', animSpeed: 16 }, + { name: 'arrow', celFile: 'Arrow', animSpeed: 16, trans: 0 }, + { name: 'lightningjavelin', celFile: 'LightningJavelin', animSpeed: 16 }, ] as const -export async function bakeMissiles(projectRoot: string = process.cwd()): Promise> { - const mpqPath = join(projectRoot, 'samples', 'd2', 'd2data.mpq') - const mpq = await MpqArchive.open(await fileSource(mpqPath)) +const PAGE_SIZE = 4096 - const palFile = mpq.find('data/global/palette/ACT1/pal.pl2') - if (!palFile) throw new Error('data/global/palette/ACT1/pal.pl2 not found in d2data.mpq') - const pl2 = decodePl2(await mpq.read(palFile)) +/** + * Shelf-pack all frames of a missile SpriteSheet into a 32-bit RGBA PNG buffer. + * Enforces Diablo II 1.13c Trans=1 transparency: + * - Pure black / background antialiasing fringe pixels (max(r,g,b) <= 4 or idx 172) are strictly transparent (alpha=0). + * - Semi-dark edge pixels ramp smoothly so no black borders or dark smudge boxes appear over the ground. + * - Core pixels remain solid (alpha=255) for vibrant spell rendering. + */ +export function packMissileSheetToRgbaPng( + sheet: SpriteSheet, + palette: Uint8Array, + trans: number = 1, +): { + png: Uint8Array + width: number + height: number + groups: [number, number, number, number, number, number][][] +} { + const frames = sheet.groups.flatMap(g => g.frames) + const widest = Math.max(1, ...frames.map(f => f.width)) + const area = frames.reduce((sum, f) => sum + (f.width + 1) * (f.height + 1), 0) + let pageWidth = Math.min(PAGE_SIZE, Math.max(widest + 2, 512)) + while (pageWidth < PAGE_SIZE && pageWidth * pageWidth < area * 1.15) { + pageWidth *= 2 + } + pageWidth = Math.min(PAGE_SIZE, pageWidth) + + let cursorX = 0 + let shelfY = 0 + let shelfHeight = 0 + const placements: { x: number; y: number; width: number; height: number }[] = [] + + for (const frame of frames) { + const w = Math.max(1, Math.min(frame.width, pageWidth)) + const h = Math.max(1, Math.min(frame.height, PAGE_SIZE)) + if (cursorX + w > pageWidth) { + shelfY += shelfHeight + 1 + shelfHeight = 0 + cursorX = 0 + } + placements.push({ x: cursorX, y: shelfY, width: w, height: h }) + cursorX += w + 1 + shelfHeight = Math.max(shelfHeight, h) + } + + const pageHeight = Math.max(1, shelfY + shelfHeight) + const rgba = new Uint8Array(pageWidth * pageHeight * 4) + + let idx = 0 + for (const frame of frames) { + const place = placements[idx]! + idx += 1 + for (let row = 0; row < place.height; row += 1) { + const fromRow = row * frame.width + const toRow = (place.y + row) * pageWidth + place.x + for (let col = 0; col < place.width; col += 1) { + const srcAt = fromRow + col + const dst = (toRow + col) * 4 + if (frame.mask[srcAt] === 0) { + rgba[dst] = 0 + rgba[dst + 1] = 0 + rgba[dst + 2] = 0 + rgba[dst + 3] = 0 + } else { + const val = frame.indices[srcAt]! + if (val === 0) { + rgba[dst] = 0 + rgba[dst + 1] = 0 + rgba[dst + 2] = 0 + rgba[dst + 3] = 0 + } else { + const r = palette[val * 3]! + const g = palette[val * 3 + 1]! + const b = palette[val * 3 + 2]! + if (trans === 1) { + const m = Math.max(r, g, b) + if (m <= 4) { + rgba[dst] = 0 + rgba[dst + 1] = 0 + rgba[dst + 2] = 0 + rgba[dst + 3] = 0 + } else { + const alpha = Math.min(255, Math.round(((m - 4) / (60 - 4)) * 255)) + rgba[dst] = r + rgba[dst + 1] = g + rgba[dst + 2] = b + rgba[dst + 3] = alpha + } + } else { + rgba[dst] = r + rgba[dst + 1] = g + rgba[dst + 2] = b + rgba[dst + 3] = 255 + } + } + } + } + } + } + + const groups: [number, number, number, number, number, number][][] = [] + let consumed = 0 + for (const group of sheet.groups) { + const gList: [number, number, number, number, number, number][] = [] + for (let i = 0; i < group.frames.length; i += 1) { + const p = placements[consumed]! + const f = group.frames[i]! + consumed += 1 + gList.push([p.x, p.y, p.width, p.height, f.anchorX ?? 0, f.anchorY ?? 0]) + } + groups.push(gList) + } + + const png = encodeRgbaPng({ width: pageWidth, height: pageHeight, pixels: rgba }) + return { png, width: pageWidth, height: pageHeight, groups } +} + +function formatMetaTs(meta: MissileMeta): string { + const groupsStr = meta.groups + .map( + group => + ` [\n${group.map(f => ` [${f.join(', ')}]`).join(',\n')}\n ]`, + ) + .join(',\n') + + return `{\n name: ${JSON.stringify(meta.name)},\n celFile: ${JSON.stringify(meta.celFile)},\n width: ${meta.width},\n height: ${meta.height},\n directions: ${meta.directions},\n framesPerDirection: ${meta.framesPerDirection},\n animSpeed: ${meta.animSpeed},\n groups: [\n${groupsStr}\n ],\n}` +} + +export async function bakeMissiles(projectRoot: string = process.cwd()): Promise> { + const archivePaths = [ + join(projectRoot, 'samples', 'd2', 'Patch_D2.mpq'), + join(projectRoot, 'samples', 'd2', 'd2exp.mpq'), + join(projectRoot, 'samples', 'd2', 'd2data.mpq'), + ] + const archives: MpqArchive[] = [] + for (const p of archivePaths) { + try { + archives.push(await MpqArchive.open(await fileSource(p))) + } catch { + // ignore + } + } + + async function readMpqFile(path: string): Promise { + for (const a of archives) { + const f = a.find(path) + if (f) return a.read(f) + } + return null + } + + const palBytes = await readMpqFile('data/global/palette/ACT1/pal.pl2') + if (!palBytes) throw new Error('data/global/palette/ACT1/pal.pl2 not found in MPQ archives') + const pl2 = decodePl2(palBytes) const publicOutDir = join(projectRoot, 'public', 'missiles') const packOutDir = join(projectRoot, 'samples', 'd2-packs', 'missiles') @@ -74,10 +255,10 @@ export async function bakeMissiles(projectRoot: string = process.cwd()): Promise const metaRecord: Record = {} for (const target of MISSILE_TARGETS) { - const f = mpq.find(`data/global/missiles/${target.celFile}.dcc`) - if (!f) throw new Error(`Missile DCC not found: data/global/missiles/${target.celFile}.dcc`) + const raw = await readMpqFile(`data/global/missiles/${target.celFile}.dcc`) + if (!raw) throw new Error(`Missile DCC not found: data/global/missiles/${target.celFile}.dcc`) - const dcc = decodeDcc(await mpq.read(f)) + const dcc = decodeDcc(raw) const groups = dcc.directions.map(dir => ({ frames: dir.frames.map( (frame): SpriteFrame => ({ @@ -92,7 +273,8 @@ export async function bakeMissiles(projectRoot: string = process.cwd()): Promise })) const sheet: SpriteSheet = { groups, width: null } - const packed = packSheetToPng(sheet, pl2.rgb) + const trans = 'trans' in target ? (target as any).trans : 1 + const packed = packMissileSheetToRgbaPng(sheet, pl2.rgb, trans) const meta: MissileMeta = { name: target.name, @@ -118,6 +300,15 @@ export async function bakeMissiles(projectRoot: string = process.cwd()): Promise } // Generate src/render/missiles-meta.ts + const metaExports = MISSILE_TARGETS.map(t => { + const upper = t.name.toUpperCase() + return `export const ${upper}_META: MissileMeta = ${formatMetaTs(metaRecord[t.name]!)}` + }).join('\n\n') + + const mapEntries = MISSILE_TARGETS.map(t => { + return ` '${t.name}': ${t.name.toUpperCase()}_META,` + }).join('\n') + const metaTsContent = `/** * Authentic Diablo II v1.13c Missile Atlas Metadata. * Auto-generated by scripts/pack-missiles.ts. @@ -157,12 +348,32 @@ export interface MissileMeta { * The engine's 64-direction space -> DCC direction tables. * Ported from OpenDiablo2 d2fileformats/d2dcc/dcc_dir_lookup.go (Dir64ToDcc). */ -const DIR64_TO_DCC_16: readonly number[] = [ - 4, 4, 8, 8, 8, 8, 0, 0, 0, 0, 9, 9, 9, 9, 5, 5, - 5, 5, 10, 10, 10, 10, 1, 1, 1, 1, 11, 11, 11, 11, 6, 6, - 6, 6, 12, 12, 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, 7, 7, - 7, 7, 14, 14, 14, 14, 3, 3, 3, 3, 15, 15, 15, 15, 4, 4, -] +const DIR64_TO_DCC: Readonly> = { + 4: [ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, + ], + 8: [ + 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, + 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, + 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, + 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, + ], + 16: [ + 4, 4, 8, 8, 8, 8, 0, 0, 0, 0, 9, 9, 9, 9, 5, 5, + 5, 5, 10, 10, 10, 10, 1, 1, 1, 1, 11, 11, 11, 11, 6, 6, + 6, 6, 12, 12, 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, 7, 7, + 7, 7, 14, 14, 14, 14, 3, 3, 3, 3, 15, 15, 15, 15, 4, 4, + ], + 32: [ + 4, 16, 16, 8, 8, 17, 17, 0, 0, 18, 18, 9, 9, 19, 19, 5, + 5, 20, 20, 10, 10, 21, 21, 1, 1, 22, 22, 11, 11, 23, 23, 6, + 6, 24, 24, 12, 12, 25, 25, 2, 2, 26, 26, 13, 13, 27, 27, 7, + 7, 28, 28, 14, 14, 29, 29, 3, 3, 30, 30, 15, 15, 31, 31, 4, + ], +} /** * Calculate DCC direction index for a missile based on 2D velocity vector. @@ -179,35 +390,36 @@ export function velocityToDccDirection(vx: number, vy: number, directions = 16): // Map angle so that South (PI/2) is 0, turning clockwise const fraction = (angle - Math.PI / 2) / (2 * Math.PI) const dir64 = Math.round((((fraction % 1) + 1) % 1) * 64) % 64 - if (directions === 16) { - return DIR64_TO_DCC_16[dir64] ?? 0 + const table = DIR64_TO_DCC[directions] + if (table !== undefined) { + return table[dir64] ?? 0 } return 0 } -export const FIREBOLT_META: MissileMeta = ${JSON.stringify(metaRecord['firebolt'], null, 2)} +${metaExports} -export const FIREBALL_META: MissileMeta = ${JSON.stringify(metaRecord['fireball'], null, 2)} - -export const FIREEXPLODE_META: MissileMeta = ${JSON.stringify(metaRecord['fireexplode'], null, 2)} - -export const MISSILE_METAS: Readonly> = { - firebolt: FIREBOLT_META, - fireball: FIREBALL_META, - fireexplode: FIREEXPLODE_META, -} +export const MISSILE_METAS: Readonly> = Object.freeze({ +${mapEntries} +}) ` - const metaTsPath = join(projectRoot, 'src', 'render', 'missiles-meta.ts') - writeFileSync(metaTsPath, metaTsContent, 'utf-8') - console.log(`[Missile Packer] Wrote ${metaTsPath}`) + + const outTsPath = join(projectRoot, 'src', 'render', 'missiles-meta.ts') + writeFileSync(outTsPath, metaTsContent, 'utf-8') + console.log(`[Missile Packer] Wrote ${outTsPath}`) return metaRecord } -// Execute standalone if called from CLI -if (process.argv[1]?.endsWith('pack-missiles.ts')) { - bakeMissiles().catch((err: unknown) => { - console.error('Bake missiles failed:', err) - process.exit(1) - }) +// Direct invocation via tsx +if (import.meta.url === `file://${process.argv[1]}`) { + bakeMissiles() + .then(() => { + console.log('[Missile Packer] All missile assets baked successfully.') + process.exit(0) + }) + .catch(err => { + console.error('[Missile Packer] Failed:', err) + process.exit(1) + }) } diff --git a/scripts/png.ts b/scripts/png.ts index 2a124a3..1fe9ee2 100644 --- a/scripts/png.ts +++ b/scripts/png.ts @@ -170,3 +170,65 @@ export function encodeIndexedPng(image: IndexedImage): Uint8Array { for (const part of parts) { out.set(part, offset); offset += part.byteLength } return out } + +/** An RGBA image ready to encode. */ +export interface RgbaImage { + /** Width in pixels. */ + readonly width: number + /** Height in pixels. */ + readonly height: number + /** RGBA pixels, row-major, 4 bytes per pixel (`width * height * 4` bytes). */ + readonly pixels: Uint8Array +} + +/** + * Encode a 32-bit RGBA image as a PNG (color type 6). + * + * @param image - the RGBA image. + * @returns the PNG bytes. + */ +export function encodeRgbaPng(image: RgbaImage): Uint8Array { + const { width, height, pixels } = image + if (pixels.byteLength !== width * height * 4) { + throw new Error(`pixel buffer is ${String(pixels.byteLength)} bytes for ${String(width)}x${String(height)} RGBA`) + } + + const ihdr = new Uint8Array(13) + const ihdrView = new DataView(ihdr.buffer) + ihdrView.setUint32(0, width) + ihdrView.setUint32(4, height) + ihdr[8] = 8 // bit depth + ihdr[9] = 6 // colour type: RGBA + ihdr[10] = 0 // deflate + ihdr[11] = 0 // adaptive filtering + ihdr[12] = 0 // no interlace + + const stride = 4 + const raw = new Uint8Array((width * stride + 1) * height) + const candidate = new Uint8Array(width * stride) + let at = 0 + for (let y = 0; y < height; y += 1) { + const row = pixels.subarray(y * width * stride, (y + 1) * width * stride) + const previous = y === 0 ? null : pixels.subarray((y - 1) * width * stride, y * width * stride) + let bestType = 0 + let bestScore = Number.POSITIVE_INFINITY + for (const type of [0, 1, 2]) { + filterRow(type, row, previous, stride, candidate) + const value = score(candidate) + if (value < bestScore) { bestScore = value; bestType = type } + } + filterRow(bestType, row, previous, stride, candidate) + raw[at] = bestType + raw.set(candidate, at + 1) + at += width * stride + 1 + } + + const idat = new Uint8Array(deflateSync(raw, { level: 9 })) + const parts = [SIGNATURE, chunk('IHDR', ihdr), chunk('IDAT', idat), chunk('IEND', new Uint8Array(0))] + const size = parts.reduce((sum, part) => sum + part.byteLength, 0) + const out = new Uint8Array(size) + let offset = 0 + for (const part of parts) { out.set(part, offset); offset += part.byteLength } + return out +} + diff --git a/src/game/class-starter-profiles.ts b/src/game/class-starter-profiles.ts index 07dfe8a..7e5ee4c 100644 --- a/src/game/class-starter-profiles.ts +++ b/src/game/class-starter-profiles.ts @@ -18,7 +18,15 @@ import type { CharacterClassCode } from './classes.ts' import type { EquipSlotId, GridPlacement, UiInventoryItem } from '../ui/inventory.ts' import type { CharacterAttributes } from '../ui/character-sheet.ts' -import type { HotkeySkillEntry } from '../ui/hotkeys.ts' +import { + type HotkeySkillEntry, + DEFAULT_SORCERESS_SKILLS, + isLeftUsableSkill, + isPassiveSkill, + isAuraSkill, +} from '../ui/hotkeys.ts' +import { SKILLS_BY_CLASS } from '../data/skills-catalog.ts' +import { calculateManaCost } from './skill-calc-engine.ts' export interface ClassProfileState { readonly classCode: CharacterClassCode @@ -1648,124 +1656,46 @@ export const CLASS_STARTER_HARD_POINTS: Record = { - ama: [ - { skillId: 0, name: 'Attack', nameZh: '普通攻击', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 2, name: 'Throw', nameZh: '投掷', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 3, name: 'Unsummon', nameZh: '取消召唤', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 6, name: 'Magic Arrow', nameZh: '魔法箭', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 7, name: 'Fire Arrow', nameZh: '火箭', level: 1, manaCost: 3, leftUsable: true, rightUsable: true }, - { skillId: 11, name: 'Cold Arrow', nameZh: '冰箭', level: 1, manaCost: 3.5, leftUsable: true, rightUsable: true }, - { skillId: 12, name: 'Multiple Shot', nameZh: '多重箭', level: 10, manaCost: 13, leftUsable: true, rightUsable: true }, - { skillId: 22, name: 'Guided Arrow', nameZh: '导引箭', level: 20, manaCost: 8, leftUsable: true, rightUsable: true }, - { skillId: 26, name: 'Strafe', nameZh: '炮轰', level: 10, manaCost: 11, leftUsable: true, rightUsable: true }, - { skillId: 31, name: 'Freezing Arrow', nameZh: '冻结箭', level: 10, manaCost: 17, leftUsable: true, rightUsable: true }, - { skillId: 10, name: 'Jab', nameZh: '戳刺', level: 1, manaCost: 2, leftUsable: true, rightUsable: true }, - { skillId: 24, name: 'Charged Strike', nameZh: '充能一击', level: 5, manaCost: 5, leftUsable: true, rightUsable: true }, - { skillId: 35, name: 'Lightning Fury', nameZh: '闪电之怒', level: 10, manaCost: 14, leftUsable: true, rightUsable: true }, - { skillId: 8, name: 'Inner Sight', nameZh: '内视', level: 1, manaCost: 5, leftUsable: false, rightUsable: true }, - { skillId: 17, name: 'Slow Missiles', nameZh: '减速箭', level: 1, manaCost: 5, leftUsable: false, rightUsable: true }, - { skillId: 28, name: 'Decoy', nameZh: '诱饵', level: 1, manaCost: 19, leftUsable: false, rightUsable: true }, - { skillId: 32, name: 'Valkyrie', nameZh: '女武神', level: 10, manaCost: 34, leftUsable: false, rightUsable: true }, - ], - sor: [ - { skillId: 0, name: 'Attack', nameZh: '普通攻击', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 2, name: 'Throw', nameZh: '投掷', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 3, name: 'Unsummon', nameZh: '取消召唤', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 36, name: 'Fire Bolt', nameZh: '火弹', level: 5, manaCost: 2.5, leftUsable: true, rightUsable: true }, - { skillId: 47, name: 'Fire Ball', nameZh: '火球', level: 8, manaCost: 8.5, leftUsable: true, rightUsable: true }, - { skillId: 56, name: 'Meteor', nameZh: '陨石', level: 6, manaCost: 22, leftUsable: true, rightUsable: true }, - { skillId: 38, name: 'Charged Bolt', nameZh: '充能弹', level: 4, manaCost: 4, leftUsable: true, rightUsable: true }, - { skillId: 49, name: 'Lightning', nameZh: '闪电', level: 7, manaCost: 11, leftUsable: true, rightUsable: true }, - { skillId: 54, name: 'Teleport', nameZh: '传送', level: 4, manaCost: 21, leftUsable: false, rightUsable: true }, - { skillId: 44, name: 'Frost Nova', nameZh: '霜之新星', level: 3, manaCost: 11, leftUsable: false, rightUsable: true }, - { skillId: 59, name: 'Blizzard', nameZh: '暴风雪', level: 10, manaCost: 27, leftUsable: true, rightUsable: true }, - { skillId: 64, name: 'Frozen Orb', nameZh: '冰封球', level: 12, manaCost: 30, leftUsable: true, rightUsable: true }, - { skillId: 40, name: 'Frozen Armor', nameZh: '冰封装甲', level: 3, manaCost: 7, leftUsable: false, rightUsable: true }, - { skillId: 42, name: 'Static Field', nameZh: '静态力场', level: 5, manaCost: 9, leftUsable: false, rightUsable: true }, - ], - nec: [ - { skillId: 0, name: 'Attack', nameZh: '普通攻击', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 2, name: 'Throw', nameZh: '投掷', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 3, name: 'Unsummon', nameZh: '取消召唤', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 66, name: 'Amplify Damage', nameZh: '伤害加深', level: 1, manaCost: 4, leftUsable: false, rightUsable: true }, - { skillId: 67, name: 'Teeth', nameZh: '牙', level: 5, manaCost: 5, leftUsable: true, rightUsable: true }, - { skillId: 68, name: 'Bone Armor', nameZh: '白骨装甲', level: 1, manaCost: 11, leftUsable: false, rightUsable: true }, - { skillId: 70, name: 'Raise Skeleton', nameZh: '复生骷髅', level: 20, manaCost: 15, leftUsable: false, rightUsable: true }, - { skillId: 74, name: 'Corpse Explosion', nameZh: '尸体爆炸', level: 10, manaCost: 15, leftUsable: true, rightUsable: true }, - { skillId: 75, name: 'Clay Golem', nameZh: '粘土石魔', level: 1, manaCost: 15, leftUsable: false, rightUsable: true }, - { skillId: 80, name: 'Raise Skeletal Mage', nameZh: '复生骷髅法师', level: 5, manaCost: 12, leftUsable: false, rightUsable: true }, - { skillId: 84, name: 'Bone Spear', nameZh: '骨矛', level: 15, manaCost: 12, leftUsable: true, rightUsable: true }, - { skillId: 87, name: 'Decrepify', nameZh: '衰老', level: 1, manaCost: 11, leftUsable: false, rightUsable: true }, - { skillId: 92, name: 'Poison Nova', nameZh: '剧毒新星', level: 5, manaCost: 20, leftUsable: false, rightUsable: true }, - { skillId: 95, name: 'Revive', nameZh: '重生', level: 5, manaCost: 45, leftUsable: false, rightUsable: true }, - ], - pal: [ - { skillId: 0, name: 'Attack', nameZh: '普通攻击', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 2, name: 'Throw', nameZh: '投掷', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 3, name: 'Unsummon', nameZh: '取消召唤', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 96, name: 'Sacrifice', nameZh: '牺牲', level: 5, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 97, name: 'Smite', nameZh: '重击', level: 5, manaCost: 2, leftUsable: true, rightUsable: true }, - { skillId: 101, name: 'Holy Bolt', nameZh: '圣光弹', level: 5, manaCost: 6, leftUsable: true, rightUsable: true }, - { skillId: 106, name: 'Zeal', nameZh: '热忱', level: 5, manaCost: 2, leftUsable: true, rightUsable: true }, - { skillId: 107, name: 'Charge', nameZh: '突击', level: 1, manaCost: 9, leftUsable: true, rightUsable: true }, - { skillId: 112, name: 'Blessed Hammer', nameZh: '祝福之槌', level: 20, manaCost: 10, leftUsable: true, rightUsable: true }, - { skillId: 117, name: 'Holy Shield', nameZh: '圣盾', level: 15, manaCost: 35, leftUsable: false, rightUsable: true }, - { skillId: 98, name: 'Might', nameZh: '力量灵气', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 113, name: 'Concentration', nameZh: '专注灵气', level: 20, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 115, name: 'Vigor', nameZh: '活力灵气', level: 15, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 122, name: 'Fanaticism', nameZh: '狂热灵气', level: 10, manaCost: 0, leftUsable: false, rightUsable: true }, - ], - bar: [ - { skillId: 0, name: 'Attack', nameZh: '普通攻击', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 2, name: 'Throw', nameZh: '投掷', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 3, name: 'Unsummon', nameZh: '取消召唤', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 126, name: 'Bash', nameZh: '重击', level: 5, manaCost: 2, leftUsable: true, rightUsable: true }, - { skillId: 130, name: 'Howl', nameZh: '狂嚎', level: 1, manaCost: 4, leftUsable: false, rightUsable: true }, - { skillId: 132, name: 'Leap', nameZh: '跳跃', level: 1, manaCost: 2, leftUsable: false, rightUsable: true }, - { skillId: 133, name: 'Double Swing', nameZh: '双手挥击', level: 5, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 138, name: 'Shout', nameZh: '大叫', level: 15, manaCost: 6, leftUsable: false, rightUsable: true }, - { skillId: 143, name: 'Leap Attack', nameZh: '跳跃攻击', level: 1, manaCost: 9, leftUsable: true, rightUsable: true }, - { skillId: 144, name: 'Concentrate', nameZh: '专心', level: 5, manaCost: 2, leftUsable: true, rightUsable: true }, - { skillId: 147, name: 'Frenzy', nameZh: '狂乱', level: 10, manaCost: 3, leftUsable: true, rightUsable: true }, - { skillId: 149, name: 'Battle Orders', nameZh: '战斗体制', level: 20, manaCost: 7, leftUsable: false, rightUsable: true }, - { skillId: 151, name: 'Whirlwind', nameZh: '旋风', level: 20, manaCost: 25, leftUsable: true, rightUsable: true }, - { skillId: 152, name: 'Berserk', nameZh: '狂战士', level: 1, manaCost: 4, leftUsable: true, rightUsable: true }, - { skillId: 155, name: 'Battle Command', nameZh: '战斗指挥', level: 1, manaCost: 11, leftUsable: false, rightUsable: true }, - ], - dru: [ - { skillId: 0, name: 'Attack', nameZh: '普通攻击', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 2, name: 'Throw', nameZh: '投掷', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 3, name: 'Unsummon', nameZh: '取消召唤', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 221, name: 'Arctic Blast', nameZh: '极地风暴', level: 1, manaCost: 4, leftUsable: true, rightUsable: true }, - { skillId: 223, name: 'Werewolf', nameZh: '狼人变化', level: 5, manaCost: 15, leftUsable: false, rightUsable: true }, - { skillId: 225, name: 'Firestorm', nameZh: '火风暴', level: 5, manaCost: 4, leftUsable: true, rightUsable: true }, - { skillId: 226, name: 'Oak Sage', nameZh: '橡木智者', level: 15, manaCost: 20, leftUsable: false, rightUsable: true }, - { skillId: 227, name: 'Cyclone Armor', nameZh: '飓风装甲', level: 15, manaCost: 15, leftUsable: false, rightUsable: true }, - { skillId: 229, name: 'Molten Boulder', nameZh: '熔火巨石', level: 5, manaCost: 10, leftUsable: true, rightUsable: true }, - { skillId: 235, name: 'Twister', nameZh: '龙卷风', level: 15, manaCost: 7, leftUsable: true, rightUsable: true }, - { skillId: 237, name: 'Summon Dire Wolf', nameZh: '召唤狂狼', level: 5, manaCost: 20, leftUsable: false, rightUsable: true }, - { skillId: 240, name: 'Tornado', nameZh: '暴风', level: 20, manaCost: 10, leftUsable: true, rightUsable: true }, - { skillId: 245, name: 'Hurricane', nameZh: '毁灭风暴', level: 20, manaCost: 30, leftUsable: false, rightUsable: true }, - { skillId: 247, name: 'Summon Grizzly', nameZh: '召唤灰熊', level: 5, manaCost: 40, leftUsable: false, rightUsable: true }, - ], - ass: [ - { skillId: 0, name: 'Attack', nameZh: '普通攻击', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 2, name: 'Throw', nameZh: '投掷', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, - { skillId: 3, name: 'Unsummon', nameZh: '取消召唤', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, - { skillId: 251, name: 'Fire Blast', nameZh: '火焰爆震', level: 15, manaCost: 3, leftUsable: true, rightUsable: true }, - { skillId: 254, name: 'Tiger Strike', nameZh: '虎击', level: 5, manaCost: 1, leftUsable: true, rightUsable: true }, - { skillId: 255, name: 'Dragon Talon', nameZh: '龙爪', level: 5, manaCost: 6, leftUsable: true, rightUsable: true }, - { skillId: 256, name: 'Shock Web', nameZh: '电能网', level: 15, manaCost: 6, leftUsable: true, rightUsable: true }, - { skillId: 258, name: 'Burst of Speed', nameZh: '速度爆发', level: 5, manaCost: 10, leftUsable: false, rightUsable: true }, - { skillId: 260, name: 'Dragon Claw', nameZh: '双龙爪', level: 5, manaCost: 2, leftUsable: true, rightUsable: true }, - { skillId: 261, name: 'Charged Bolt Sentry', nameZh: '电能守卫', level: 15, manaCost: 13, leftUsable: false, rightUsable: true }, - { skillId: 264, name: 'Cloak of Shadows', nameZh: '魔影斗篷', level: 1, manaCost: 13, leftUsable: false, rightUsable: true }, - { skillId: 267, name: 'Fade', nameZh: '能量消解', level: 5, manaCost: 10, leftUsable: false, rightUsable: true }, - { skillId: 271, name: 'Lightning Sentry', nameZh: '雷电守卫', level: 20, manaCost: 20, leftUsable: false, rightUsable: true }, - { skillId: 276, name: 'Death Sentry', nameZh: '亡者守卫', level: 20, manaCost: 20, leftUsable: false, rightUsable: true }, - { skillId: 279, name: 'Shadow Master', nameZh: '暗影大师', level: 5, manaCost: 35, leftUsable: false, rightUsable: true }, - ], + ama: buildClassDefaultSkills('ama'), + sor: DEFAULT_SORCERESS_SKILLS, + nec: buildClassDefaultSkills('nec'), + pal: buildClassDefaultSkills('pal'), + bar: buildClassDefaultSkills('bar'), + dru: buildClassDefaultSkills('dru'), + ass: buildClassDefaultSkills('ass'), } // ------------------------------------------------------------------------------------------------- diff --git a/src/game/combat.ts b/src/game/combat.ts index 162b67a..d0b1c1b 100644 --- a/src/game/combat.ts +++ b/src/game/combat.ts @@ -141,6 +141,12 @@ export interface Monster { corpseTicks: number /** Whether the monster is sleeping (inactive off-screen room). */ sleeping?: boolean | undefined + /** Ticks remaining frozen (cannot move or attack). */ + frozenTicks?: number | undefined + /** Ticks remaining chilled (slowed movement). */ + chillTicks?: number | undefined + /** Ticks remaining poisoned (damage over time). */ + poisonTicks?: number | undefined } /** The player's combat-relevant state. */ @@ -840,6 +846,20 @@ function tickMonsters(world: CombatWorld, options: CombatOptions, terrain: Comba } if (monster.hitFlash > 0) monster.hitFlash -= 1 if (monster.cooldown > 0) monster.cooldown -= 1 + if (monster.frozenTicks !== undefined && monster.frozenTicks > 0) { + monster.frozenTicks -= 1 + monster.state = 'idle' + continue + } + if (monster.chillTicks !== undefined && monster.chillTicks > 0) { + monster.chillTicks -= 1 + } + if (monster.poisonTicks !== undefined && monster.poisonTicks > 0) { + monster.poisonTicks -= 1 + if (world.tick % 5 === 0 && monster.hp > 1) { + monster.hp -= 1 + } + } if (options.disableMonsterAggro) { monster.state = 'idle' @@ -876,7 +896,8 @@ function tickMonsters(world: CombatWorld, options: CombatOptions, terrain: Comba continue } monster.state = 'chase' - const step = monster.stats.speed / 25 + const chillFactor = monster.chillTicks !== undefined && monster.chillTicks > 0 ? 0.5 : 1 + const step = (monster.stats.speed / 25) * chillFactor const movedMonster = moveWithCollision(monster, (dx / distance) * step, (dy / distance) * step, terrain) monster.x = movedMonster.x monster.y = movedMonster.y diff --git a/src/game/engine.ts b/src/game/engine.ts index 949e246..bafa244 100644 --- a/src/game/engine.ts +++ b/src/game/engine.ts @@ -2,7 +2,7 @@ import { tickCombat, createWorld, spawnMonsters, spawnMonsterPacks, damageMonste import type { CombatWorld, CombatOptions, MonsterPack, MonsterStats, SafeZone } from './combat.ts' import { Inventory, rollDrop, goldItem, totalStat } from './items.ts' import type { Item, ItemBase, Affix } from './items.ts' -import { castSkill, tickProjectiles } from './skills.ts' +import { castSkill, tickProjectiles, CANONICAL_113C_MISSILES, ISO_GROUND_ASPECT_RATIO } from './skills.ts' import type { SkillDef, Projectile } from './skills.ts' import { QuestLog, npcDialog } from './quests.ts' import type { NpcDef, QuestDef } from './quests.ts' @@ -323,21 +323,77 @@ export class GameEngine { this.projectiles.length = 0 this.projectiles.push(...outcome.alive) for (const hit of outcome.hits) { + const targetMonster = this.world.monsters.find(m => m.index === hit.targetIndex) + if (hit.isUndeadOnly) { + const name = targetMonster?.stats?.name?.toLowerCase() ?? '' + const id = targetMonster?.stats?.id?.toLowerCase() ?? '' + const isUndead = (targetMonster as any)?.isUndead || + name.includes('skeleton') || name.includes('zombie') || name.includes('ghoul') || name.includes('ghost') || name.includes('wraith') || + id.includes('skeleton') || id.includes('zombie') || id.includes('ghoul') || id.includes('ghost') || id.includes('wraith') + if (!isUndead) { + continue + } + } + damageMonster(this.world, hit.targetIndex, hit.damage) this.metrics.castHits += 1 + + if (targetMonster) { + if (hit.statusEffect === 'freeze') { + targetMonster.frozenTicks = hit.statusDuration ?? 75 + } else if (hit.statusEffect === 'chill') { + targetMonster.chillTicks = hit.statusDuration ?? 100 + } else if (hit.statusEffect === 'poison') { + targetMonster.poisonTicks = hit.statusDuration ?? 100 + } + } + + // AoE splash damage + if (hit.aoeRadius && hit.aoeRadius > 0) { + for (const m of this.world.monsters) { + if (m.index === hit.targetIndex || m.state === 'dead' || m.hp <= 0) continue + if (hit.isUndeadOnly) { + const name = m?.stats?.name?.toLowerCase() ?? '' + const id = m?.stats?.id?.toLowerCase() ?? '' + const isUndead = (m as any)?.isUndead || + name.includes('skeleton') || name.includes('zombie') || name.includes('ghoul') || name.includes('ghost') || name.includes('wraith') || + id.includes('skeleton') || id.includes('zombie') || id.includes('ghoul') || id.includes('ghost') || id.includes('wraith') + if (!isUndead) continue + } + // Ground distance in 2:1 isometric projection: + // dx^2 + (dy / ISO_GROUND_ASPECT_RATIO)^2 <= aoeRadius^2 + const dx = m.x - hit.x + const dy = (m.y - hit.y) / ISO_GROUND_ASPECT_RATIO + if (Math.hypot(dx, dy) <= hit.aoeRadius) { + damageMonster(this.world, m.index, hit.damage) + if (hit.statusEffect === 'freeze') { + m.frozenTicks = hit.statusDuration ?? 75 + } else if (hit.statusEffect === 'chill') { + m.chillTicks = hit.statusDuration ?? 100 + } else if (hit.statusEffect === 'poison') { + m.poisonTicks = hit.statusDuration ?? 100 + } + } + } + } + const missileType = hit.missileType ?? (hit.skillId === '36' || hit.skillId === 'firebolt' ? 'firebolt' : undefined) - if (missileType === 'firebolt' || hit.skillId === '36' || hit.skillId === 'firebolt') { + const mslData = missileType ? CANONICAL_113C_MISSILES[missileType] : undefined + const explType = mslData?.explosionMissile || (missileType === 'firebolt' ? 'fireexplode' : '') + if (explType) { + const explData = CANONICAL_113C_MISSILES[explType] + const maxFrames = explData?.animLen || 12 this.explosions.push({ - missileType: 'fireexplode', + missileType: explType, x: hit.x, y: hit.y, frame: 0, - maxFrames: 12, - radius: 24, + maxFrames, + radius: hit.aoeRadius ?? 24, }) this.world.events.push({ kind: 'missileExplode', - missileType: 'fireexplode', + missileType: explType, skillId: hit.skillId, x: hit.x, y: hit.y, @@ -345,21 +401,34 @@ export class GameEngine { }) } } + if (outcome.wallHitEvents) { for (const wallHit of outcome.wallHitEvents) { + if (wallHit.aoeRadius && wallHit.aoeRadius > 0) { + for (const m of this.world.monsters) { + if (m.state === 'dead' || m.hp <= 0) continue + if (Math.hypot(m.x - wallHit.x, m.y - wallHit.y) <= wallHit.aoeRadius) { + damageMonster(this.world, m.index, 10) + } + } + } const missileType = wallHit.missileType ?? (wallHit.skillId === '36' || wallHit.skillId === 'firebolt' ? 'firebolt' : undefined) - if (missileType === 'firebolt' || wallHit.skillId === '36' || wallHit.skillId === 'firebolt') { + const mslData = missileType ? CANONICAL_113C_MISSILES[missileType] : undefined + const explType = mslData?.explosionMissile || (missileType === 'firebolt' ? 'fireexplode' : '') + if (explType) { + const explData = CANONICAL_113C_MISSILES[explType] + const maxFrames = explData?.animLen || 12 this.explosions.push({ - missileType: 'fireexplode', + missileType: explType, x: wallHit.x, y: wallHit.y, frame: 0, - maxFrames: 12, - radius: 24, + maxFrames, + radius: wallHit.aoeRadius ?? 24, }) this.world.events.push({ kind: 'missileExplode', - missileType: 'fireexplode', + missileType: explType, skillId: wallHit.skillId, x: wallHit.x, y: wallHit.y, @@ -605,7 +674,7 @@ export class GameEngine { } const amount = entity.amount || 1 this.groundItems.remove(id) - const gIdx = this.ground.findIndex(g => Math.hypot(g.x - entity.x, g.y - entity.y) <= 16) + const gIdx = this.ground.findIndex(g => Math.hypot(g.x - entity.x, g.y - entity.y) <= 32 || (g.item as any)?.isGold) if (gIdx !== -1) { this.ground.splice(gIdx, 1) } @@ -639,7 +708,7 @@ export class GameEngine { } this.groundItems.remove(id) - const gIdx = this.ground.findIndex(g => Math.hypot(g.x - entity.x, g.y - entity.y) <= 16) + const gIdx = this.ground.findIndex(g => Math.hypot(g.x - entity.x, g.y - entity.y) <= 32 || g.item === entity.item) if (gIdx !== -1) { this.ground.splice(gIdx, 1) } diff --git a/src/game/engine/missile-engine.ts b/src/game/engine/missile-engine.ts index bfb9ea0..b755d51 100644 --- a/src/game/engine/missile-engine.ts +++ b/src/game/engine/missile-engine.ts @@ -285,18 +285,19 @@ export class MissileEngine { startX: m.x, startY: m.y, targetX: m.x + Math.cos(subAngle) * 100, - targetY: m.y + Math.sin(subAngle) * 100, + targetY: m.y + Math.sin(subAngle) * (100 * 0.5), dmgPacket: m.dmgPacket, }) subMissilesSpawned.push(subName) } // Spiral flight for Blessed Hammer (`blessedhammer`, `skillId = 112`) + // In 2:1 isometric ground perspective, vertical expansion is foreshortened by 0.5. if (m.sourceSkillId === 112 || m.name.toLowerCase() === 'blessedhammer') { m.angleRad += 0.24 const radius = 14 + m.ageTicks * 4 m.x += Math.cos(m.angleRad) * (radius * 0.25) - m.y += Math.sin(m.angleRad) * (radius * 0.25) + m.y += Math.sin(m.angleRad) * (radius * 0.25 * 0.5) } else { m.x += m.vx m.y += m.vy diff --git a/src/game/skills.ts b/src/game/skills.ts index c8d8531..ec902a1 100644 --- a/src/game/skills.ts +++ b/src/game/skills.ts @@ -72,8 +72,43 @@ export interface Projectile { readonly fromPlayer: boolean /** Optional missile type / token (e.g. 'firebolt'). */ readonly missileType?: string | undefined + /** Pierces through enemies without expiring until range or wall hit. */ + readonly pierce?: boolean | undefined + /** Set of monster indices already hit by this projectile (for pierce/nextHit). */ + readonly hitTargets?: Set | undefined + /** Area of effect splash radius in pixels upon impact. */ + readonly aoeRadius?: number | undefined + /** Elemental status effect applied on hit: chill, freeze, poison. */ + readonly statusEffect?: 'chill' | 'freeze' | 'poison' | undefined + /** Duration in ticks of the status effect. */ + readonly statusDuration?: number | undefined + /** Homing missile: steers towards nearest alive monster. */ + readonly homing?: boolean | undefined + /** Archimedean spiral trajectory (e.g. Blessed Hammer). */ + readonly spiral?: { + readonly originX: number + readonly originY: number + readonly angle: number + readonly radius: number + } | undefined + /** Random perpendicular trajectory wobble (e.g. Charged Bolt). */ + readonly jitter?: boolean | undefined + /** Target restriction: only hits undead monsters. */ + readonly isUndeadOnly?: boolean | undefined } +/** + * In Diablo II's 2:1 isometric projection (orthogonal diamond grid: 80x40 cells, 16x8 sub-tiles), + * any horizontal circular curve on the map ground plane projects into scene-pixel coordinates + * as an ellipse with a 2:1 aspect ratio (vertical scale / horizontal scale = 8 / 16 = 0.5). + * + * NOTE: The calculated coordinates (x, y) are physical MAP coordinates on the level plane, + * NOT the rendered sprite icon offsets. Rendered icons are pre-rendered 2.5D DCC billboards + * positioned via sprite frame anchors, while map coordinates govern physical trajectory and collision. + */ +export const ISO_GROUND_ASPECT_RATIO = 0.5 + + /** What a cast produced. */ export type CastResult = | { readonly kind: 'mana'; readonly cost: number } @@ -144,6 +179,26 @@ export const CANONICAL_113C_MISSILES: Readonly> = speedPxPerSec: 500, distancePx: 1000, }, + fireball: { + name: 'fireball', + id: 62, + vel: 20, + maxVel: 20, + range: 50, + levRange: 0, + celFile: 'Fireball', + animLen: 5, + animSpeed: 16, + loopAnim: 1, + numDirections: 16, + explosionMissile: 'fireexplode', + light: 7, + red: 255, + green: 178, + blue: 64, + speedPxPerSec: 500, + distancePx: 1000, + }, fireexplode: { name: 'fireexplode', id: 29, @@ -164,6 +219,466 @@ export const CANONICAL_113C_MISSILES: Readonly> = speedPxPerSec: 0, distancePx: 0, }, + explodingarrowexp: { + name: 'explodingarrowexp', + id: 47, + vel: 0, + maxVel: 0, + range: 12, + levRange: 0, + celFile: 'FireArrowExplode2', + animLen: 12, + animSpeed: 16, + loopAnim: 0, + numDirections: 1, + explosionMissile: '', + light: 13, + red: 255, + green: 178, + blue: 64, + speedPxPerSec: 0, + distancePx: 0, + }, + icebolt: { + name: 'icebolt', + id: 59, + vel: 12, + maxVel: 12, + range: 50, + levRange: 0, + celFile: 'Icebolt', + animLen: 6, + animSpeed: 16, + loopAnim: 1, + numDirections: 16, + explosionMissile: 'iceexplode', + light: 7, + red: 81, + green: 81, + blue: 255, + speedPxPerSec: 300, + distancePx: 600, + }, + iceblast: { + name: 'iceblast', + id: 91, + vel: 12, + maxVel: 12, + range: 50, + levRange: 0, + celFile: 'IceBlast', + animLen: 5, + animSpeed: 16, + loopAnim: 1, + numDirections: 16, + explosionMissile: 'freezeexplode', + light: 7, + red: 81, + green: 81, + blue: 255, + speedPxPerSec: 300, + distancePx: 600, + }, + glacialspike: { + name: 'glacialspike', + id: 96, + vel: 16, + maxVel: 16, + range: 40, + levRange: 0, + celFile: 'GlacialSpike', + animLen: 6, + animSpeed: 16, + loopAnim: 1, + numDirections: 16, + explosionMissile: 'freezeexplode', + light: 5, + red: 81, + green: 81, + blue: 255, + speedPxPerSec: 400, + distancePx: 640, + }, + iceexplode: { + name: 'iceexplode', + id: 30, + vel: 0, + maxVel: 0, + range: 16, + levRange: 0, + celFile: 'IceArrowExplode', + animLen: 16, + animSpeed: 16, + loopAnim: 0, + numDirections: 1, + explosionMissile: '', + light: 11, + red: 81, + green: 81, + blue: 255, + speedPxPerSec: 0, + distancePx: 0, + }, + freezeexplode: { + name: 'freezeexplode', + id: 88, + vel: 0, + maxVel: 0, + range: 15, + levRange: 0, + celFile: 'FreezeExplodeCenter', + animLen: 15, + animSpeed: 16, + loopAnim: 0, + numDirections: 1, + explosionMissile: '', + light: 11, + red: 81, + green: 81, + blue: 255, + speedPxPerSec: 0, + distancePx: 0, + }, + freezingarrowexp1: { + name: 'freezingarrowexp1', + id: 88, + vel: 0, + maxVel: 0, + range: 15, + levRange: 0, + celFile: 'FreezeExplodeCenter', + animLen: 15, + animSpeed: 16, + loopAnim: 0, + numDirections: 1, + explosionMissile: '', + light: 11, + red: 81, + green: 81, + blue: 255, + speedPxPerSec: 0, + distancePx: 0, + }, + chargedbolt: { + name: 'chargedbolt', + id: 56, + vel: 12, + maxVel: 12, + range: 98, + levRange: 0, + celFile: 'ChargedBolt', + animLen: 10, + animSpeed: 16, + loopAnim: 1, + numDirections: 16, + explosionMissile: '', + light: 3, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 300, + distancePx: 1176, + }, + teeth: { + name: 'teeth', + id: 114, + vel: 16, + maxVel: 16, + range: 50, + levRange: 0, + celFile: 'teethMissile', + animLen: 30, + animSpeed: 16, + loopAnim: 0, + numDirections: 32, + explosionMissile: 'teethexplode', + light: 3, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 400, + distancePx: 800, + }, + teethexplode: { + name: 'teethexplode', + id: 204, + vel: 0, + maxVel: 0, + range: 13, + levRange: 0, + celFile: 'teethexplode', + animLen: 13, + animSpeed: 16, + loopAnim: 0, + numDirections: 1, + explosionMissile: '', + light: 0, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 0, + distancePx: 0, + }, + bonespear: { + name: 'bonespear', + id: 192, + vel: 24, + maxVel: 24, + range: 40, + levRange: 0, + celFile: 'BoneSpear', + animLen: 6, + animSpeed: 16, + loopAnim: 1, + numDirections: 16, + explosionMissile: 'teethexplode', + light: 3, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 600, + distancePx: 960, + }, + bonespearexplode: { + name: 'bonespearexplode', + id: 216, + vel: 0, + maxVel: 0, + range: 13, + levRange: 0, + celFile: 'teethexplode', + animLen: 13, + animSpeed: 16, + loopAnim: 0, + numDirections: 1, + explosionMissile: '', + light: 0, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 0, + distancePx: 0, + }, + bonespirit: { + name: 'bonespirit', + id: 193, + vel: 12, + maxVel: 12, + range: 128, + levRange: 0, + celFile: 'BoneSpirit', + animLen: 8, + animSpeed: 16, + loopAnim: 1, + numDirections: 8, + explosionMissile: 'bonespiritexplode', + light: 3, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 300, + distancePx: 1536, + }, + bonespiritexplode: { + name: 'bonespiritexplode', + id: 327, + vel: 0, + maxVel: 0, + range: 13, + levRange: 0, + celFile: 'BoneSpiritExplode', + animLen: 13, + animSpeed: 16, + loopAnim: 0, + numDirections: 1, + explosionMissile: '', + light: 0, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 0, + distancePx: 0, + }, + poisonnova: { + name: 'poisonnova', + id: 118, + vel: 12, + maxVel: 12, + range: 30, + levRange: 0, + celFile: 'poisonNova', + animLen: 30, + animSpeed: 16, + loopAnim: 0, + numDirections: 32, + explosionMissile: '', + light: 0, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 300, + distancePx: 360, + }, + holybolt: { + name: 'holybolt', + id: 55, + vel: 20, + maxVel: 20, + range: 50, + levRange: 0, + celFile: 'HolyBoltMissile', + animLen: 16, + animSpeed: 16, + loopAnim: 1, + numDirections: 1, + explosionMissile: '', + light: 7, + red: 222, + green: 222, + blue: 255, + speedPxPerSec: 500, + distancePx: 1000, + }, + blessedhammer: { + name: 'blessedhammer', + id: 92, + vel: 18, + maxVel: 30, + range: 120, + levRange: 0, + celFile: 'blessedhammer', + animLen: 6, + animSpeed: 16, + loopAnim: 1, + numDirections: 16, + explosionMissile: '', + light: 5, + red: 222, + green: 222, + blue: 255, + speedPxPerSec: 450, + distancePx: 2160, + }, + magicarrow: { + name: 'magicarrow', + id: 27, + vel: 24, + maxVel: 24, + range: 40, + levRange: 0, + celFile: 'SafeArrow', + animLen: 1, + animSpeed: 16, + loopAnim: 0, + numDirections: 32, + explosionMissile: 'teethexplode', + light: 0, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 600, + distancePx: 960, + }, + firearrow: { + name: 'firearrow', + id: 12, + vel: 24, + maxVel: 24, + range: 40, + levRange: 0, + celFile: 'FireArrow', + animLen: 8, + animSpeed: 16, + loopAnim: 0, + numDirections: 32, + explosionMissile: 'fireexplode', + light: 6, + red: 255, + green: 178, + blue: 64, + speedPxPerSec: 600, + distancePx: 960, + }, + icearrow: { + name: 'icearrow', + id: 28, + vel: 24, + maxVel: 24, + range: 40, + levRange: 0, + celFile: 'IceArrow', + animLen: 8, + animSpeed: 16, + loopAnim: 0, + numDirections: 32, + explosionMissile: 'iceexplode', + light: 6, + red: 81, + green: 81, + blue: 255, + speedPxPerSec: 600, + distancePx: 960, + }, + arrow: { + name: 'arrow', + id: 0, + vel: 24, + maxVel: 24, + range: 40, + levRange: 0, + celFile: 'Arrow', + animLen: 1, + animSpeed: 16, + loopAnim: 0, + numDirections: 32, + explosionMissile: '', + light: 0, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 600, + distancePx: 960, + }, + multipleshotarrow: { + name: 'multipleshotarrow', + id: 213, + vel: 24, + maxVel: 24, + range: 50, + levRange: 0, + celFile: 'Arrow', + animLen: 1, + animSpeed: 16, + loopAnim: 0, + numDirections: 32, + explosionMissile: '', + light: 0, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 600, + distancePx: 1200, + }, + lightningjavelin: { + name: 'lightningjavelin', + id: 205, + vel: 30, + maxVel: 30, + range: 25, + levRange: 0, + celFile: 'LightningJavelin', + animLen: 5, + animSpeed: 16, + loopAnim: 1, + numDirections: 16, + explosionMissile: '', + light: 6, + red: 255, + green: 255, + blue: 255, + speedPxPerSec: 750, + distancePx: 750, + }, }) /** @@ -543,6 +1058,10 @@ export interface ProjectileOutcome { readonly y: number readonly skillId?: string | undefined readonly missileType?: string | undefined + readonly aoeRadius?: number | undefined + readonly statusEffect?: 'chill' | 'freeze' | 'poison' | undefined + readonly statusDuration?: number | undefined + readonly isUndeadOnly?: boolean | undefined }[] /** Projectiles that died on a wall or expired. */ readonly expired: number @@ -554,6 +1073,7 @@ export interface ProjectileOutcome { readonly y: number readonly skillId?: string | undefined readonly missileType?: string | undefined + readonly aoeRadius?: number | undefined }[] | undefined } @@ -583,23 +1103,97 @@ export function tickProjectiles( y: number skillId?: string | undefined missileType?: string | undefined + aoeRadius?: number | undefined + statusEffect?: 'chill' | 'freeze' | 'poison' | undefined + statusDuration?: number | undefined + isUndeadOnly?: boolean | undefined }[] = [] const wallHitEvents: { x: number y: number skillId?: string | undefined missileType?: string | undefined + aoeRadius?: number | undefined }[] = [] let expired = 0 let wallHits = 0 for (const projectile of projectiles) { if (projectile.ttl <= 0) { expired += 1; continue } - const x = projectile.x + projectile.vx - const y = projectile.y + projectile.vy - const moved: Projectile = { ...projectile, x, y, ttl: projectile.ttl - 1 } + + let vx = projectile.vx + let vy = projectile.vy + let x = projectile.x + vx + let y = projectile.y + vy + let spiral = projectile.spiral + + // 1. Archimedean spiral trajectory (e.g. Blessed Hammer) + // The hammer traces an Archimedean spiral on the map ground plane. In oblique/isometric + // perspective (2:1 projection), a circular ground expansion projects to an ellipse with a 2:1 aspect ratio. + if (spiral !== undefined) { + const nextAngle = spiral.angle + 0.22 + const nextRadius = spiral.radius + 3.2 + spiral = { ...spiral, angle: nextAngle, radius: nextRadius } + x = spiral.originX + Math.cos(nextAngle) * nextRadius + y = spiral.originY + Math.sin(nextAngle) * (nextRadius * ISO_GROUND_ASPECT_RATIO) + vx = -Math.sin(nextAngle) * 18 + vy = Math.cos(nextAngle) * (18 * ISO_GROUND_ASPECT_RATIO) + } else if (projectile.homing) { + // 2. Homing trajectory (e.g. Bone Spirit) - smoothly steer towards closest living enemy + let nearestDist = Number.POSITIVE_INFINITY + let targetX = 0 + let targetY = 0 + let foundTarget = false + for (const t of targets) { + if (!t.alive) continue + const d = Math.hypot(t.x - projectile.x, t.y - projectile.y) + if (d < nearestDist && d > 4) { + nearestDist = d + targetX = t.x + targetY = t.y + foundTarget = true + } + } + if (foundTarget) { + const curAngle = Math.atan2(vy, vx) + const targetAngle = Math.atan2(targetY - projectile.y, targetX - projectile.x) + let diff = targetAngle - curAngle + while (diff > Math.PI) diff -= 2 * Math.PI + while (diff < -Math.PI) diff += 2 * Math.PI + const maxTurn = 0.14 + const turn = Math.max(-maxTurn, Math.min(maxTurn, diff)) + const newAngle = curAngle + turn + const speed = Math.hypot(vx, vy) + vx = Math.cos(newAngle) * speed + vy = Math.sin(newAngle) * speed + x = projectile.x + vx + y = projectile.y + vy + } + } else if (projectile.jitter) { + // 3. Jitter trajectory (e.g. Charged Bolt) - sinusoidal perpendicular wiggle on the ground plane + const perpX = -vy + const perpY = vx + const speed = Math.hypot(vx, vy) + if (speed > 0) { + const wobble = Math.sin(projectile.ttl * 0.8) * 1.5 + x += (perpX / speed) * wobble + y += (perpY / speed) * (wobble * ISO_GROUND_ASPECT_RATIO) + } + } + + const hitTargets = projectile.hitTargets ?? new Set() + const moved: Projectile = { + ...projectile, + x, + y, + vx, + vy, + spiral, + hitTargets, + ttl: projectile.ttl - 1, + } + // Walls first: a projectile dies against missile barriers (solid walls, closed doors) - // while passing freely over ground-only barriers (rivers, lava, chasms) via COLLIDE_MASK_MISSILE. const blockedByTerrain = options.isMissileBlocked !== undefined ? options.isMissileBlocked(x, y, projectile.x, projectile.y) @@ -611,13 +1205,17 @@ export function tickProjectiles( y, skillId: projectile.skillId, missileType: projectile.missileType, + aoeRadius: projectile.aoeRadius, }) continue } + let struck = false for (const target of targets) { if (!target.alive) continue + if (hitTargets.has(target.index)) continue // already struck by piercing projectile if (Math.hypot(target.x - x, target.y - y) > target.radius + radius) continue + hits.push({ targetIndex: target.index, damage: projectile.damage, @@ -625,11 +1223,22 @@ export function tickProjectiles( y, skillId: projectile.skillId, missileType: projectile.missileType, + aoeRadius: projectile.aoeRadius, + statusEffect: projectile.statusEffect, + statusDuration: projectile.statusDuration, + isUndeadOnly: projectile.isUndeadOnly, }) - struck = true - break + + hitTargets.add(target.index) + if (!projectile.pierce) { + struck = true + break + } + } + + if (!struck) { + alive.push(moved) } - if (!struck) alive.push(moved) } return { alive, hits, expired, wallHits, wallHitEvents } } diff --git a/src/render/missiles-meta.ts b/src/render/missiles-meta.ts index 824506d..096e279 100644 --- a/src/render/missiles-meta.ts +++ b/src/render/missiles-meta.ts @@ -37,12 +37,32 @@ export interface MissileMeta { * The engine's 64-direction space -> DCC direction tables. * Ported from OpenDiablo2 d2fileformats/d2dcc/dcc_dir_lookup.go (Dir64ToDcc). */ -const DIR64_TO_DCC_16: readonly number[] = [ - 4, 4, 8, 8, 8, 8, 0, 0, 0, 0, 9, 9, 9, 9, 5, 5, - 5, 5, 10, 10, 10, 10, 1, 1, 1, 1, 11, 11, 11, 11, 6, 6, - 6, 6, 12, 12, 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, 7, 7, - 7, 7, 14, 14, 14, 14, 3, 3, 3, 3, 15, 15, 15, 15, 4, 4, -] +const DIR64_TO_DCC: Readonly> = { + 4: [ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, + ], + 8: [ + 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, + 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, + 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, + 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, + ], + 16: [ + 4, 4, 8, 8, 8, 8, 0, 0, 0, 0, 9, 9, 9, 9, 5, 5, + 5, 5, 10, 10, 10, 10, 1, 1, 1, 1, 11, 11, 11, 11, 6, 6, + 6, 6, 12, 12, 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, 7, 7, + 7, 7, 14, 14, 14, 14, 3, 3, 3, 3, 15, 15, 15, 15, 4, 4, + ], + 32: [ + 4, 16, 16, 8, 8, 17, 17, 0, 0, 18, 18, 9, 9, 19, 19, 5, + 5, 20, 20, 10, 10, 21, 21, 1, 1, 22, 22, 11, 11, 23, 23, 6, + 6, 24, 24, 12, 12, 25, 25, 2, 2, 26, 26, 13, 13, 27, 27, 7, + 7, 28, 28, 14, 14, 29, 29, 3, 3, 30, 30, 15, 15, 31, 31, 4, + ], +} /** * Calculate DCC direction index for a missile based on 2D velocity vector. @@ -59,1492 +79,4731 @@ export function velocityToDccDirection(vx: number, vy: number, directions = 16): // Map angle so that South (PI/2) is 0, turning clockwise const fraction = (angle - Math.PI / 2) / (2 * Math.PI) const dir64 = Math.round((((fraction % 1) + 1) % 1) * 64) % 64 - if (directions === 16) { - return DIR64_TO_DCC_16[dir64] ?? 0 + const table = DIR64_TO_DCC[directions] + if (table !== undefined) { + return table[dir64] ?? 0 } return 0 } export const FIREBOLT_META: MissileMeta = { - "name": "firebolt", - "celFile": "Firebolt", - "width": 512, - "height": 439, - "directions": 16, - "framesPerDirection": 5, - "animSpeed": 16, - "groups": [ + name: "firebolt", + celFile: "Firebolt", + width: 512, + height: 439, + directions: 16, + framesPerDirection: 5, + animSpeed: 16, + groups: [ [ - [ - 0, - 0, - 55, - 39, - -12, - -71 - ], - [ - 56, - 0, - 55, - 39, - -12, - -71 - ], - [ - 112, - 0, - 55, - 39, - -12, - -71 - ], - [ - 168, - 0, - 55, - 39, - -12, - -71 - ], - [ - 224, - 0, - 55, - 39, - -12, - -71 - ] + [0, 0, 55, 39, -12, -71], + [56, 0, 55, 39, -12, -71], + [112, 0, 55, 39, -12, -71], + [168, 0, 55, 39, -12, -71], + [224, 0, 55, 39, -12, -71] ], [ - [ - 280, - 0, - 63, - 41, - -12, - -55 - ], - [ - 344, - 0, - 63, - 41, - -12, - -55 - ], - [ - 408, - 0, - 63, - 41, - -12, - -55 - ], - [ - 0, - 42, - 63, - 41, - -12, - -55 - ], - [ - 64, - 42, - 63, - 41, - -12, - -55 - ] + [280, 0, 63, 41, -12, -55], + [344, 0, 63, 41, -12, -55], + [408, 0, 63, 41, -12, -55], + [0, 42, 63, 41, -12, -55], + [64, 42, 63, 41, -12, -55] ], [ - [ - 128, - 42, - 62, - 41, - -49, - -56 - ], - [ - 191, - 42, - 62, - 41, - -49, - -56 - ], - [ - 254, - 42, - 62, - 41, - -49, - -56 - ], - [ - 317, - 42, - 62, - 41, - -49, - -56 - ], - [ - 380, - 42, - 62, - 41, - -49, - -56 - ] + [128, 42, 62, 41, -49, -56], + [191, 42, 62, 41, -49, -56], + [254, 42, 62, 41, -49, -56], + [317, 42, 62, 41, -49, -56], + [380, 42, 62, 41, -49, -56] ], [ - [ - 443, - 42, - 56, - 40, - -44, - -71 - ], - [ - 0, - 84, - 56, - 40, - -44, - -71 - ], - [ - 57, - 84, - 56, - 40, - -44, - -71 - ], - [ - 114, - 84, - 56, - 40, - -44, - -71 - ], - [ - 171, - 84, - 56, - 40, - -44, - -71 - ] + [443, 42, 56, 40, -44, -71], + [0, 84, 56, 40, -44, -71], + [57, 84, 56, 40, -44, -71], + [114, 84, 56, 40, -44, -71], + [171, 84, 56, 40, -44, -71] ], [ - [ - 228, - 84, - 30, - 45, - -15, - -76 - ], - [ - 259, - 84, - 30, - 45, - -15, - -76 - ], - [ - 290, - 84, - 30, - 45, - -15, - -76 - ], - [ - 321, - 84, - 30, - 45, - -15, - -76 - ], - [ - 352, - 84, - 30, - 45, - -15, - -76 - ] + [228, 84, 30, 45, -15, -76], + [259, 84, 30, 45, -15, -76], + [290, 84, 30, 45, -15, -76], + [321, 84, 30, 45, -15, -76], + [352, 84, 30, 45, -15, -76] ], [ - [ - 383, - 84, - 71, - 30, - -13, - -58 - ], - [ - 0, - 130, - 71, - 30, - -13, - -58 - ], - [ - 72, - 130, - 71, - 30, - -13, - -58 - ], - [ - 144, - 130, - 71, - 30, - -13, - -58 - ], - [ - 216, - 130, - 71, - 30, - -13, - -58 - ] + [383, 84, 71, 30, -13, -58], + [0, 130, 71, 30, -13, -58], + [72, 130, 71, 30, -13, -58], + [144, 130, 71, 30, -13, -58], + [216, 130, 71, 30, -13, -58] ], [ - [ - 288, - 130, - 32, - 46, - -15, - -56 - ], - [ - 321, - 130, - 32, - 46, - -15, - -56 - ], - [ - 354, - 130, - 32, - 46, - -15, - -56 - ], - [ - 387, - 130, - 32, - 46, - -15, - -56 - ], - [ - 420, - 130, - 32, - 46, - -15, - -56 - ] + [288, 130, 32, 46, -15, -56], + [321, 130, 32, 46, -15, -56], + [354, 130, 32, 46, -15, -56], + [387, 130, 32, 46, -15, -56], + [420, 130, 32, 46, -15, -56] ], [ - [ - 0, - 177, - 71, - 28, - -57, - -57 - ], - [ - 72, - 177, - 71, - 28, - -57, - -57 - ], - [ - 144, - 177, - 71, - 28, - -57, - -57 - ], - [ - 216, - 177, - 71, - 28, - -57, - -57 - ], - [ - 288, - 177, - 71, - 28, - -57, - -57 - ] + [0, 177, 71, 28, -57, -57], + [72, 177, 71, 28, -57, -57], + [144, 177, 71, 28, -57, -57], + [216, 177, 71, 28, -57, -57], + [288, 177, 71, 28, -57, -57] ], [ - [ - 360, - 177, - 42, - 44, - -12, - -75 - ], - [ - 403, - 177, - 42, - 44, - -12, - -75 - ], - [ - 446, - 177, - 42, - 44, - -12, - -75 - ], - [ - 0, - 222, - 42, - 44, - -12, - -75 - ], - [ - 43, - 222, - 42, - 44, - -12, - -75 - ] + [360, 177, 42, 44, -12, -75], + [403, 177, 42, 44, -12, -75], + [446, 177, 42, 44, -12, -75], + [0, 222, 42, 44, -12, -75], + [43, 222, 42, 44, -12, -75] ], [ - [ - 86, - 222, - 68, - 33, - -14, - -65 - ], - [ - 155, - 222, - 68, - 33, - -14, - -65 - ], - [ - 224, - 222, - 68, - 33, - -14, - -65 - ], - [ - 293, - 222, - 68, - 33, - -14, - -65 - ], - [ - 362, - 222, - 68, - 33, - -14, - -65 - ] + [86, 222, 68, 33, -14, -65], + [155, 222, 68, 33, -14, -65], + [224, 222, 68, 33, -14, -65], + [293, 222, 68, 33, -14, -65], + [362, 222, 68, 33, -14, -65] ], [ - [ - 431, - 222, - 69, - 32, - -12, - -56 - ], - [ - 0, - 267, - 69, - 32, - -12, - -56 - ], - [ - 70, - 267, - 69, - 32, - -12, - -56 - ], - [ - 140, - 267, - 69, - 32, - -12, - -56 - ], - [ - 210, - 267, - 69, - 32, - -12, - -56 - ] + [431, 222, 69, 32, -12, -56], + [0, 267, 69, 32, -12, -56], + [70, 267, 69, 32, -12, -56], + [140, 267, 69, 32, -12, -56], + [210, 267, 69, 32, -12, -56] ], [ - [ - 280, - 267, - 49, - 45, - -12, - -55 - ], - [ - 330, - 267, - 49, - 45, - -12, - -55 - ], - [ - 380, - 267, - 49, - 45, - -12, - -55 - ], - [ - 430, - 267, - 49, - 45, - -12, - -55 - ], - [ - 0, - 313, - 49, - 45, - -12, - -55 - ] + [280, 267, 49, 45, -12, -55], + [330, 267, 49, 45, -12, -55], + [380, 267, 49, 45, -12, -55], + [430, 267, 49, 45, -12, -55], + [0, 313, 49, 45, -12, -55] ], [ - [ - 50, - 313, - 47, - 45, - -35, - -55 - ], - [ - 98, - 313, - 47, - 45, - -35, - -55 - ], - [ - 146, - 313, - 47, - 45, - -35, - -55 - ], - [ - 194, - 313, - 47, - 45, - -35, - -55 - ], - [ - 242, - 313, - 47, - 45, - -35, - -55 - ] + [50, 313, 47, 45, -35, -55], + [98, 313, 47, 45, -35, -55], + [146, 313, 47, 45, -35, -55], + [194, 313, 47, 45, -35, -55], + [242, 313, 47, 45, -35, -55] ], [ - [ - 290, - 313, - 71, - 36, - -58, - -56 - ], - [ - 362, - 313, - 71, - 36, - -58, - -56 - ], - [ - 434, - 313, - 71, - 36, - -58, - -56 - ], - [ - 0, - 359, - 71, - 36, - -58, - -56 - ], - [ - 72, - 359, - 71, - 36, - -58, - -56 - ] + [290, 313, 71, 36, -58, -56], + [362, 313, 71, 36, -58, -56], + [434, 313, 71, 36, -58, -56], + [0, 359, 71, 36, -58, -56], + [72, 359, 71, 36, -58, -56] ], [ - [ - 144, - 359, - 67, - 35, - -54, - -65 - ], - [ - 212, - 359, - 67, - 35, - -54, - -65 - ], - [ - 280, - 359, - 67, - 35, - -54, - -65 - ], - [ - 348, - 359, - 67, - 35, - -54, - -65 - ], - [ - 416, - 359, - 67, - 35, - -54, - -65 - ] + [144, 359, 67, 35, -54, -65], + [212, 359, 67, 35, -54, -65], + [280, 359, 67, 35, -54, -65], + [348, 359, 67, 35, -54, -65], + [416, 359, 67, 35, -54, -65] ], [ - [ - 0, - 396, - 44, - 43, - -32, - -74 - ], - [ - 45, - 396, - 44, - 43, - -32, - -74 - ], - [ - 90, - 396, - 44, - 43, - -32, - -74 - ], - [ - 135, - 396, - 44, - 43, - -32, - -74 - ], - [ - 180, - 396, - 44, - 43, - -32, - -74 - ] + [0, 396, 44, 43, -32, -74], + [45, 396, 44, 43, -32, -74], + [90, 396, 44, 43, -32, -74], + [135, 396, 44, 43, -32, -74], + [180, 396, 44, 43, -32, -74] ] - ] + ], } export const FIREBALL_META: MissileMeta = { - "name": "fireball", - "celFile": "Fireball", - "width": 1024, - "height": 335, - "directions": 16, - "framesPerDirection": 5, - "animSpeed": 16, - "groups": [ + name: "fireball", + celFile: "Fireball", + width: 1024, + height: 335, + directions: 16, + framesPerDirection: 5, + animSpeed: 16, + groups: [ [ - [ - 0, - 0, - 75, - 48, - -19, - -74 - ], - [ - 76, - 0, - 75, - 48, - -19, - -74 - ], - [ - 152, - 0, - 75, - 48, - -19, - -74 - ], - [ - 228, - 0, - 75, - 48, - -19, - -74 - ], - [ - 304, - 0, - 75, - 48, - -19, - -74 - ] + [0, 0, 75, 48, -19, -74], + [76, 0, 75, 48, -19, -74], + [152, 0, 75, 48, -19, -74], + [228, 0, 75, 48, -19, -74], + [304, 0, 75, 48, -19, -74] ], [ - [ - 380, - 0, - 79, - 52, - -19, - -62 - ], - [ - 460, - 0, - 79, - 52, - -19, - -62 - ], - [ - 540, - 0, - 79, - 52, - -19, - -62 - ], - [ - 620, - 0, - 79, - 52, - -19, - -62 - ], - [ - 700, - 0, - 79, - 52, - -19, - -62 - ] + [380, 0, 79, 52, -19, -62], + [460, 0, 79, 52, -19, -62], + [540, 0, 79, 52, -19, -62], + [620, 0, 79, 52, -19, -62], + [700, 0, 79, 52, -19, -62] ], [ - [ - 780, - 0, - 81, - 52, - -63, - -61 - ], - [ - 862, - 0, - 81, - 52, - -63, - -61 - ], - [ - 0, - 53, - 81, - 52, - -63, - -61 - ], - [ - 82, - 53, - 81, - 52, - -63, - -61 - ], - [ - 164, - 53, - 81, - 52, - -63, - -61 - ] + [780, 0, 81, 52, -63, -61], + [862, 0, 81, 52, -63, -61], + [0, 53, 81, 52, -63, -61], + [82, 53, 81, 52, -63, -61], + [164, 53, 81, 52, -63, -61] ], [ - [ - 246, - 53, - 74, - 48, - -55, - -74 - ], - [ - 321, - 53, - 74, - 48, - -55, - -74 - ], - [ - 396, - 53, - 74, - 48, - -55, - -74 - ], - [ - 471, - 53, - 74, - 48, - -55, - -74 - ], - [ - 546, - 53, - 74, - 48, - -55, - -74 - ] + [246, 53, 74, 48, -55, -74], + [321, 53, 74, 48, -55, -74], + [396, 53, 74, 48, -55, -74], + [471, 53, 74, 48, -55, -74], + [546, 53, 74, 48, -55, -74] ], [ - [ - 621, - 53, - 34, - 55, - -17, - -81 - ], - [ - 656, - 53, - 34, - 55, - -17, - -81 - ], - [ - 691, - 53, - 34, - 55, - -17, - -81 - ], - [ - 726, - 53, - 34, - 55, - -17, - -81 - ], - [ - 761, - 53, - 34, - 55, - -17, - -81 - ] + [621, 53, 34, 55, -17, -81], + [656, 53, 34, 55, -17, -81], + [691, 53, 34, 55, -17, -81], + [726, 53, 34, 55, -17, -81], + [761, 53, 34, 55, -17, -81] ], [ - [ - 796, - 53, - 94, - 40, - -20, - -65 - ], - [ - 891, - 53, - 94, - 40, - -20, - -65 - ], - [ - 0, - 109, - 94, - 40, - -20, - -65 - ], - [ - 95, - 109, - 94, - 40, - -20, - -65 - ], - [ - 190, - 109, - 94, - 40, - -20, - -65 - ] + [796, 53, 94, 40, -20, -65], + [891, 53, 94, 40, -20, -65], + [0, 109, 94, 40, -20, -65], + [95, 109, 94, 40, -20, -65], + [190, 109, 94, 40, -20, -65] ], [ - [ - 285, - 109, - 40, - 61, - -20, - -63 - ], - [ - 326, - 109, - 40, - 61, - -20, - -63 - ], - [ - 367, - 109, - 40, - 61, - -20, - -63 - ], - [ - 408, - 109, - 40, - 61, - -20, - -63 - ], - [ - 449, - 109, - 40, - 61, - -20, - -63 - ] + [285, 109, 40, 61, -20, -63], + [326, 109, 40, 61, -20, -63], + [367, 109, 40, 61, -20, -63], + [408, 109, 40, 61, -20, -63], + [449, 109, 40, 61, -20, -63] ], [ - [ - 490, - 109, - 91, - 37, - -72, - -63 - ], - [ - 582, - 109, - 91, - 37, - -72, - -63 - ], - [ - 674, - 109, - 91, - 37, - -72, - -63 - ], - [ - 766, - 109, - 91, - 37, - -72, - -63 - ], - [ - 858, - 109, - 91, - 37, - -72, - -63 - ] + [490, 109, 91, 37, -72, -63], + [582, 109, 91, 37, -72, -63], + [674, 109, 91, 37, -72, -63], + [766, 109, 91, 37, -72, -63], + [858, 109, 91, 37, -72, -63] ], [ - [ - 950, - 109, - 53, - 53, - -17, - -79 - ], - [ - 0, - 171, - 53, - 53, - -17, - -79 - ], - [ - 54, - 171, - 53, - 53, - -17, - -79 - ], - [ - 108, - 171, - 53, - 53, - -17, - -79 - ], - [ - 162, - 171, - 53, - 53, - -17, - -79 - ] + [950, 109, 53, 53, -17, -79], + [0, 171, 53, 53, -17, -79], + [54, 171, 53, 53, -17, -79], + [108, 171, 53, 53, -17, -79], + [162, 171, 53, 53, -17, -79] ], [ - [ - 216, - 171, - 88, - 41, - -19, - -68 - ], - [ - 305, - 171, - 88, - 41, - -19, - -68 - ], - [ - 394, - 171, - 88, - 41, - -19, - -68 - ], - [ - 483, - 171, - 88, - 41, - -19, - -68 - ], - [ - 572, - 171, - 88, - 41, - -19, - -68 - ] + [216, 171, 88, 41, -19, -68], + [305, 171, 88, 41, -19, -68], + [394, 171, 88, 41, -19, -68], + [483, 171, 88, 41, -19, -68], + [572, 171, 88, 41, -19, -68] ], [ - [ - 661, - 171, - 89, - 45, - -19, - -62 - ], - [ - 751, - 171, - 89, - 45, - -19, - -62 - ], - [ - 841, - 171, - 89, - 45, - -19, - -62 - ], - [ - 931, - 171, - 89, - 45, - -19, - -62 - ], - [ - 0, - 225, - 89, - 45, - -19, - -62 - ] + [661, 171, 89, 45, -19, -62], + [751, 171, 89, 45, -19, -62], + [841, 171, 89, 45, -19, -62], + [931, 171, 89, 45, -19, -62], + [0, 225, 89, 45, -19, -62] ], [ - [ - 90, - 225, - 59, - 57, - -17, - -62 - ], - [ - 150, - 225, - 59, - 57, - -17, - -62 - ], - [ - 210, - 225, - 59, - 57, - -17, - -62 - ], - [ - 270, - 225, - 59, - 57, - -17, - -62 - ], - [ - 330, - 225, - 59, - 57, - -17, - -62 - ] + [90, 225, 59, 57, -17, -62], + [150, 225, 59, 57, -17, -62], + [210, 225, 59, 57, -17, -62], + [270, 225, 59, 57, -17, -62], + [330, 225, 59, 57, -17, -62] ], [ - [ - 390, - 225, - 59, - 59, - -42, - -62 - ], - [ - 450, - 225, - 59, - 59, - -42, - -62 - ], - [ - 510, - 225, - 59, - 59, - -42, - -62 - ], - [ - 570, - 225, - 59, - 59, - -42, - -62 - ], - [ - 630, - 225, - 59, - 59, - -42, - -62 - ] + [390, 225, 59, 59, -42, -62], + [450, 225, 59, 59, -42, -62], + [510, 225, 59, 59, -42, -62], + [570, 225, 59, 59, -42, -62], + [630, 225, 59, 59, -42, -62] ], [ - [ - 690, - 225, - 92, - 43, - -72, - -61 - ], - [ - 783, - 225, - 92, - 43, - -72, - -61 - ], - [ - 876, - 225, - 92, - 43, - -72, - -61 - ], - [ - 0, - 285, - 92, - 43, - -72, - -61 - ], - [ - 93, - 285, - 92, - 43, - -72, - -61 - ] + [690, 225, 92, 43, -72, -61], + [783, 225, 92, 43, -72, -61], + [876, 225, 92, 43, -72, -61], + [0, 285, 92, 43, -72, -61], + [93, 285, 92, 43, -72, -61] ], [ - [ - 186, - 285, - 85, - 43, - -65, - -69 - ], - [ - 272, - 285, - 85, - 43, - -65, - -69 - ], - [ - 358, - 285, - 85, - 43, - -65, - -69 - ], - [ - 444, - 285, - 85, - 43, - -65, - -69 - ], - [ - 530, - 285, - 85, - 43, - -65, - -69 - ] + [186, 285, 85, 43, -65, -69], + [272, 285, 85, 43, -65, -69], + [358, 285, 85, 43, -65, -69], + [444, 285, 85, 43, -65, -69], + [530, 285, 85, 43, -65, -69] ], [ - [ - 616, - 285, - 53, - 50, - -35, - -77 - ], - [ - 670, - 285, - 53, - 50, - -35, - -77 - ], - [ - 724, - 285, - 53, - 50, - -35, - -77 - ], - [ - 778, - 285, - 53, - 50, - -35, - -77 - ], - [ - 832, - 285, - 53, - 50, - -35, - -77 - ] + [616, 285, 53, 50, -35, -77], + [670, 285, 53, 50, -35, -77], + [724, 285, 53, 50, -35, -77], + [778, 285, 53, 50, -35, -77], + [832, 285, 53, 50, -35, -77] ] - ] + ], } export const FIREEXPLODE_META: MissileMeta = { - "name": "fireexplode", - "celFile": "FireArrowExplode2", - "width": 512, - "height": 141, - "directions": 1, - "framesPerDirection": 12, - "animSpeed": 16, - "groups": [ + name: "fireexplode", + celFile: "FireArrowExplode2", + width: 512, + height: 141, + directions: 1, + framesPerDirection: 12, + animSpeed: 16, + groups: [ [ - [ - 0, - 0, - 78, - 70, - -39, - -81 - ], - [ - 79, - 0, - 78, - 70, - -39, - -81 - ], - [ - 158, - 0, - 78, - 70, - -39, - -81 - ], - [ - 237, - 0, - 78, - 70, - -39, - -81 - ], - [ - 316, - 0, - 78, - 70, - -39, - -81 - ], - [ - 395, - 0, - 78, - 70, - -39, - -81 - ], - [ - 0, - 71, - 78, - 70, - -39, - -81 - ], - [ - 79, - 71, - 78, - 70, - -39, - -81 - ], - [ - 158, - 71, - 78, - 70, - -39, - -81 - ], - [ - 237, - 71, - 78, - 70, - -39, - -81 - ], - [ - 316, - 71, - 78, - 70, - -39, - -81 - ], - [ - 395, - 71, - 78, - 70, - -39, - -81 - ] + [0, 0, 78, 70, -39, -81], + [79, 0, 78, 70, -39, -81], + [158, 0, 78, 70, -39, -81], + [237, 0, 78, 70, -39, -81], + [316, 0, 78, 70, -39, -81], + [395, 0, 78, 70, -39, -81], + [0, 71, 78, 70, -39, -81], + [79, 71, 78, 70, -39, -81], + [158, 71, 78, 70, -39, -81], + [237, 71, 78, 70, -39, -81], + [316, 71, 78, 70, -39, -81], + [395, 71, 78, 70, -39, -81] ] - ] + ], } -export const MISSILE_METAS: Readonly> = { - firebolt: FIREBOLT_META, - fireball: FIREBALL_META, - fireexplode: FIREEXPLODE_META, +export const ICEBOLT_META: MissileMeta = { + name: "icebolt", + celFile: "Icebolt", + width: 512, + height: 357, + directions: 16, + framesPerDirection: 6, + animSpeed: 16, + groups: [ + [ + [0, 0, 51, 27, -18, -65], + [52, 0, 51, 27, -18, -65], + [104, 0, 51, 27, -18, -65], + [156, 0, 51, 27, -18, -65], + [208, 0, 51, 27, -18, -65], + [260, 0, 51, 27, -18, -65] + ], + [ + [312, 0, 55, 28, -17, -53], + [368, 0, 55, 28, -17, -53], + [424, 0, 55, 28, -17, -53], + [0, 29, 55, 28, -17, -53], + [56, 29, 55, 28, -17, -53], + [112, 29, 55, 28, -17, -53] + ], + [ + [168, 29, 54, 34, -37, -53], + [223, 29, 54, 34, -37, -53], + [278, 29, 54, 34, -37, -53], + [333, 29, 54, 34, -37, -53], + [388, 29, 54, 34, -37, -53], + [443, 29, 54, 34, -37, -53] + ], + [ + [0, 64, 53, 29, -35, -67], + [54, 64, 53, 29, -35, -67], + [108, 64, 53, 29, -35, -67], + [162, 64, 53, 29, -35, -67], + [216, 64, 53, 29, -35, -67], + [270, 64, 53, 29, -35, -67] + ], + [ + [324, 64, 16, 37, -8, -71], + [341, 64, 16, 37, -8, -71], + [358, 64, 16, 37, -8, -71], + [375, 64, 16, 37, -8, -71], + [392, 64, 16, 37, -8, -71], + [409, 64, 16, 37, -8, -71] + ], + [ + [426, 64, 70, 21, -24, -58], + [0, 102, 70, 21, -24, -58], + [71, 102, 70, 21, -24, -58], + [142, 102, 70, 21, -24, -58], + [213, 102, 70, 21, -24, -58], + [284, 102, 70, 21, -24, -58] + ], + [ + [355, 102, 18, 39, -9, -55], + [374, 102, 18, 39, -9, -55], + [393, 102, 18, 39, -9, -55], + [412, 102, 18, 39, -9, -55], + [431, 102, 18, 39, -9, -55], + [450, 102, 18, 39, -9, -55] + ], + [ + [0, 142, 70, 25, -46, -57], + [71, 142, 70, 25, -46, -57], + [142, 142, 70, 25, -46, -57], + [213, 142, 70, 25, -46, -57], + [284, 142, 70, 25, -46, -57], + [355, 142, 70, 25, -46, -57] + ], + [ + [426, 142, 29, 36, -10, -71], + [456, 142, 29, 36, -10, -71], + [0, 179, 29, 36, -10, -71], + [30, 179, 29, 36, -10, -71], + [60, 179, 29, 36, -10, -71], + [90, 179, 29, 36, -10, -71] + ], + [ + [120, 179, 66, 24, -23, -64], + [187, 179, 66, 24, -23, -64], + [254, 179, 66, 24, -23, -64], + [321, 179, 66, 24, -23, -64], + [388, 179, 66, 24, -23, -64], + [0, 216, 66, 24, -23, -64] + ], + [ + [67, 216, 66, 20, -22, -51], + [134, 216, 66, 20, -22, -51], + [201, 216, 66, 20, -22, -51], + [268, 216, 66, 20, -22, -51], + [335, 216, 66, 20, -22, -51], + [402, 216, 66, 20, -22, -51] + ], + [ + [469, 216, 35, 36, -9, -55], + [0, 253, 35, 36, -9, -55], + [36, 253, 35, 36, -9, -55], + [72, 253, 35, 36, -9, -55], + [108, 253, 35, 36, -9, -55], + [144, 253, 35, 36, -9, -55] + ], + [ + [180, 253, 31, 39, -22, -55], + [212, 253, 31, 39, -22, -55], + [244, 253, 31, 39, -22, -55], + [276, 253, 31, 39, -22, -55], + [308, 253, 31, 39, -22, -55], + [340, 253, 31, 39, -22, -55] + ], + [ + [372, 253, 67, 27, -45, -52], + [440, 253, 67, 27, -45, -52], + [0, 293, 67, 27, -45, -52], + [68, 293, 67, 27, -45, -52], + [136, 293, 67, 27, -45, -52], + [204, 293, 67, 27, -45, -52] + ], + [ + [272, 293, 66, 23, -43, -62], + [339, 293, 66, 23, -43, -62], + [406, 293, 66, 23, -43, -62], + [0, 321, 66, 23, -43, -62], + [67, 321, 66, 23, -43, -62], + [134, 321, 66, 23, -43, -62] + ], + [ + [201, 321, 33, 36, -23, -71], + [235, 321, 33, 36, -23, -71], + [269, 321, 33, 36, -23, -71], + [303, 321, 33, 36, -23, -71], + [337, 321, 33, 36, -23, -71], + [371, 321, 33, 36, -23, -71] + ] + ], } + +export const ICEBLAST_META: MissileMeta = { + name: "iceblast", + celFile: "IceBlast", + width: 1024, + height: 431, + directions: 16, + framesPerDirection: 5, + animSpeed: 16, + groups: [ + [ + [0, 0, 74, 54, -16, -71], + [75, 0, 74, 54, -16, -71], + [150, 0, 74, 54, -16, -71], + [225, 0, 74, 54, -16, -71], + [300, 0, 74, 54, -16, -71] + ], + [ + [375, 0, 85, 56, -14, -51], + [461, 0, 85, 56, -14, -51], + [547, 0, 85, 56, -14, -51], + [633, 0, 85, 56, -14, -51], + [719, 0, 85, 56, -14, -51] + ], + [ + [805, 0, 86, 51, -70, -51], + [892, 0, 86, 51, -70, -51], + [0, 57, 86, 51, -70, -51], + [87, 57, 86, 51, -70, -51], + [174, 57, 86, 51, -70, -51] + ], + [ + [261, 57, 72, 54, -58, -72], + [334, 57, 72, 54, -58, -72], + [407, 57, 72, 54, -58, -72], + [480, 57, 72, 54, -58, -72], + [553, 57, 72, 54, -58, -72] + ], + [ + [626, 57, 45, 59, -23, -78], + [672, 57, 45, 59, -23, -78], + [718, 57, 45, 59, -23, -78], + [764, 57, 45, 59, -23, -78], + [810, 57, 45, 59, -23, -78] + ], + [ + [856, 57, 100, 41, -16, -54], + [0, 117, 100, 41, -16, -54], + [101, 117, 100, 41, -16, -54], + [202, 117, 100, 41, -16, -54], + [303, 117, 100, 41, -16, -54] + ], + [ + [404, 117, 51, 67, -26, -51], + [456, 117, 51, 67, -26, -51], + [508, 117, 51, 67, -26, -51], + [560, 117, 51, 67, -26, -51], + [612, 117, 51, 67, -26, -51] + ], + [ + [664, 117, 101, 45, -85, -55], + [766, 117, 101, 45, -85, -55], + [868, 117, 101, 45, -85, -55], + [0, 185, 101, 45, -85, -55], + [102, 185, 101, 45, -85, -55] + ], + [ + [204, 185, 53, 57, -17, -76], + [258, 185, 53, 57, -17, -76], + [312, 185, 53, 57, -17, -76], + [366, 185, 53, 57, -17, -76], + [420, 185, 53, 57, -17, -76] + ], + [ + [474, 185, 91, 48, -16, -63], + [566, 185, 91, 48, -16, -63], + [658, 185, 91, 48, -16, -63], + [750, 185, 91, 48, -16, -63], + [842, 185, 91, 48, -16, -63] + ], + [ + [0, 243, 99, 42, -15, -50], + [100, 243, 99, 42, -15, -50], + [200, 243, 99, 42, -15, -50], + [300, 243, 99, 42, -15, -50], + [400, 243, 99, 42, -15, -50] + ], + [ + [500, 243, 63, 65, -15, -51], + [564, 243, 63, 65, -15, -51], + [628, 243, 63, 65, -15, -51], + [692, 243, 63, 65, -15, -51], + [756, 243, 63, 65, -15, -51] + ], + [ + [820, 243, 64, 62, -47, -51], + [885, 243, 64, 62, -47, -51], + [950, 243, 64, 62, -47, -51], + [0, 309, 64, 62, -47, -51], + [65, 309, 64, 62, -47, -51] + ], + [ + [130, 309, 99, 45, -83, -50], + [230, 309, 99, 45, -83, -50], + [330, 309, 99, 45, -83, -50], + [430, 309, 99, 45, -83, -50], + [530, 309, 99, 45, -83, -50] + ], + [ + [630, 309, 90, 49, -75, -65], + [721, 309, 90, 49, -75, -65], + [812, 309, 90, 49, -75, -65], + [903, 309, 90, 49, -75, -65], + [0, 372, 90, 49, -75, -65] + ], + [ + [91, 372, 52, 59, -38, -77], + [144, 372, 52, 59, -38, -77], + [197, 372, 52, 59, -38, -77], + [250, 372, 52, 59, -38, -77], + [303, 372, 52, 59, -38, -77] + ] + ], +} + +export const GLACIALSPIKE_META: MissileMeta = { + name: "glacialspike", + celFile: "GlacialSpike", + width: 1024, + height: 719, + directions: 16, + framesPerDirection: 6, + animSpeed: 16, + groups: [ + [ + [0, 0, 100, 61, -34, -88], + [101, 0, 100, 61, -34, -88], + [202, 0, 100, 61, -34, -88], + [303, 0, 100, 61, -34, -88], + [404, 0, 100, 61, -34, -88], + [505, 0, 100, 61, -34, -88] + ], + [ + [606, 0, 104, 67, -31, -63], + [711, 0, 104, 67, -31, -63], + [816, 0, 104, 67, -31, -63], + [0, 68, 104, 67, -31, -63], + [105, 68, 104, 67, -31, -63], + [210, 68, 104, 67, -31, -63] + ], + [ + [315, 68, 110, 68, -79, -62], + [426, 68, 110, 68, -79, -62], + [537, 68, 110, 68, -79, -62], + [648, 68, 110, 68, -79, -62], + [759, 68, 110, 68, -79, -62], + [870, 68, 110, 68, -79, -62] + ], + [ + [0, 137, 96, 59, -62, -86], + [97, 137, 96, 59, -62, -86], + [194, 137, 96, 59, -62, -86], + [291, 137, 96, 59, -62, -86], + [388, 137, 96, 59, -62, -86], + [485, 137, 96, 59, -62, -86] + ], + [ + [582, 137, 37, 73, -19, -94], + [620, 137, 37, 73, -19, -94], + [658, 137, 37, 73, -19, -94], + [696, 137, 37, 73, -19, -94], + [734, 137, 37, 73, -19, -94], + [772, 137, 37, 73, -19, -94] + ], + [ + [810, 137, 134, 48, -44, -71], + [0, 211, 134, 48, -44, -71], + [135, 211, 134, 48, -44, -71], + [270, 211, 134, 48, -44, -71], + [405, 211, 134, 48, -44, -71], + [540, 211, 134, 48, -44, -71] + ], + [ + [675, 211, 45, 83, -21, -67], + [721, 211, 45, 83, -21, -67], + [767, 211, 45, 83, -21, -67], + [813, 211, 45, 83, -21, -67], + [859, 211, 45, 83, -21, -67], + [905, 211, 45, 83, -21, -67] + ], + [ + [0, 295, 129, 48, -86, -69], + [130, 295, 129, 48, -86, -69], + [260, 295, 129, 48, -86, -69], + [390, 295, 129, 48, -86, -69], + [520, 295, 129, 48, -86, -69], + [650, 295, 129, 48, -86, -69] + ], + [ + [780, 295, 65, 70, -22, -93], + [846, 295, 65, 70, -22, -93], + [912, 295, 65, 70, -22, -93], + [0, 366, 65, 70, -22, -93], + [66, 366, 65, 70, -22, -93], + [132, 366, 65, 70, -22, -93] + ], + [ + [198, 366, 124, 50, -41, -81], + [323, 366, 124, 50, -41, -81], + [448, 366, 124, 50, -41, -81], + [573, 366, 124, 50, -41, -81], + [698, 366, 124, 50, -41, -81], + [823, 366, 124, 50, -41, -81] + ], + [ + [0, 437, 124, 51, -39, -60], + [125, 437, 124, 51, -39, -60], + [250, 437, 124, 51, -39, -60], + [375, 437, 124, 51, -39, -60], + [500, 437, 124, 51, -39, -60], + [625, 437, 124, 51, -39, -60] + ], + [ + [750, 437, 71, 78, -20, -65], + [822, 437, 71, 78, -20, -65], + [894, 437, 71, 78, -20, -65], + [0, 516, 71, 78, -20, -65], + [72, 516, 71, 78, -20, -65], + [144, 516, 71, 78, -20, -65] + ], + [ + [216, 516, 74, 79, -54, -65], + [291, 516, 74, 79, -54, -65], + [366, 516, 74, 79, -54, -65], + [441, 516, 74, 79, -54, -65], + [516, 516, 74, 79, -54, -65], + [591, 516, 74, 79, -54, -65] + ], + [ + [666, 516, 129, 52, -90, -59], + [796, 516, 129, 52, -90, -59], + [0, 596, 129, 52, -90, -59], + [130, 596, 129, 52, -90, -59], + [260, 596, 129, 52, -90, -59], + [390, 596, 129, 52, -90, -59] + ], + [ + [520, 596, 120, 46, -78, -78], + [641, 596, 120, 46, -78, -78], + [762, 596, 120, 46, -78, -78], + [883, 596, 120, 46, -78, -78], + [0, 649, 120, 46, -78, -78], + [121, 649, 120, 46, -78, -78] + ], + [ + [242, 649, 65, 70, -43, -93], + [308, 649, 65, 70, -43, -93], + [374, 649, 65, 70, -43, -93], + [440, 649, 65, 70, -43, -93], + [506, 649, 65, 70, -43, -93], + [572, 649, 65, 70, -43, -93] + ] + ], +} + +export const ICEEXPLODE_META: MissileMeta = { + name: "iceexplode", + celFile: "IceArrowExplode", + width: 512, + height: 332, + directions: 1, + framesPerDirection: 16, + animSpeed: 16, + groups: [ + [ + [0, 0, 83, 110, -43, -90], + [84, 0, 83, 110, -43, -90], + [168, 0, 83, 110, -43, -90], + [252, 0, 83, 110, -43, -90], + [336, 0, 83, 110, -43, -90], + [420, 0, 83, 110, -43, -90], + [0, 111, 83, 110, -43, -90], + [84, 111, 83, 110, -43, -90], + [168, 111, 83, 110, -43, -90], + [252, 111, 83, 110, -43, -90], + [336, 111, 83, 110, -43, -90], + [420, 111, 83, 110, -43, -90], + [0, 222, 83, 110, -43, -90], + [84, 222, 83, 110, -43, -90], + [168, 222, 83, 110, -43, -90], + [252, 222, 83, 110, -43, -90] + ] + ], +} + +export const FREEZEEXPLODE_META: MissileMeta = { + name: "freezeexplode", + celFile: "FreezeExplodeCenter", + width: 1024, + height: 323, + directions: 1, + framesPerDirection: 15, + animSpeed: 16, + groups: [ + [ + [0, 0, 143, 107, -75, -67], + [144, 0, 143, 107, -75, -67], + [288, 0, 143, 107, -75, -67], + [432, 0, 143, 107, -75, -67], + [576, 0, 143, 107, -75, -67], + [720, 0, 143, 107, -75, -67], + [864, 0, 143, 107, -75, -67], + [0, 108, 143, 107, -75, -67], + [144, 108, 143, 107, -75, -67], + [288, 108, 143, 107, -75, -67], + [432, 108, 143, 107, -75, -67], + [576, 108, 143, 107, -75, -67], + [720, 108, 143, 107, -75, -67], + [864, 108, 143, 107, -75, -67], + [0, 216, 143, 107, -75, -67] + ] + ], +} + +export const CHARGEDBOLT_META: MissileMeta = { + name: "chargedbolt", + celFile: "ChargedBolt", + width: 1024, + height: 744, + directions: 16, + framesPerDirection: 10, + animSpeed: 16, + groups: [ + [ + [0, 0, 58, 58, -31, -33], + [59, 0, 58, 58, -31, -33], + [118, 0, 58, 58, -31, -33], + [177, 0, 58, 58, -31, -33], + [236, 0, 58, 58, -31, -33], + [295, 0, 58, 58, -31, -33], + [354, 0, 58, 58, -31, -33], + [413, 0, 58, 58, -31, -33], + [472, 0, 58, 58, -31, -33], + [531, 0, 58, 58, -31, -33] + ], + [ + [590, 0, 62, 56, -29, -34], + [653, 0, 62, 56, -29, -34], + [716, 0, 62, 56, -29, -34], + [779, 0, 62, 56, -29, -34], + [842, 0, 62, 56, -29, -34], + [905, 0, 62, 56, -29, -34], + [0, 59, 62, 56, -29, -34], + [63, 59, 62, 56, -29, -34], + [126, 59, 62, 56, -29, -34], + [189, 59, 62, 56, -29, -34] + ], + [ + [252, 59, 67, 77, -28, -41], + [320, 59, 67, 77, -28, -41], + [388, 59, 67, 77, -28, -41], + [456, 59, 67, 77, -28, -41], + [524, 59, 67, 77, -28, -41], + [592, 59, 67, 77, -28, -41], + [660, 59, 67, 77, -28, -41], + [728, 59, 67, 77, -28, -41], + [796, 59, 67, 77, -28, -41], + [864, 59, 67, 77, -28, -41] + ], + [ + [932, 59, 64, 65, -34, -31], + [0, 137, 64, 65, -34, -31], + [65, 137, 64, 65, -34, -31], + [130, 137, 64, 65, -34, -31], + [195, 137, 64, 65, -34, -31], + [260, 137, 64, 65, -34, -31], + [325, 137, 64, 65, -34, -31], + [390, 137, 64, 65, -34, -31], + [455, 137, 64, 65, -34, -31], + [520, 137, 64, 65, -34, -31] + ], + [ + [585, 137, 65, 63, -32, -33], + [651, 137, 65, 63, -32, -33], + [717, 137, 65, 63, -32, -33], + [783, 137, 65, 63, -32, -33], + [849, 137, 65, 63, -32, -33], + [915, 137, 65, 63, -32, -33], + [0, 203, 65, 63, -32, -33], + [66, 203, 65, 63, -32, -33], + [132, 203, 65, 63, -32, -33], + [198, 203, 65, 63, -32, -33] + ], + [ + [264, 203, 64, 55, -34, -31], + [329, 203, 64, 55, -34, -31], + [394, 203, 64, 55, -34, -31], + [459, 203, 64, 55, -34, -31], + [524, 203, 64, 55, -34, -31], + [589, 203, 64, 55, -34, -31], + [654, 203, 64, 55, -34, -31], + [719, 203, 64, 55, -34, -31], + [784, 203, 64, 55, -34, -31], + [849, 203, 64, 55, -34, -31] + ], + [ + [914, 203, 62, 62, -31, -32], + [0, 267, 62, 62, -31, -32], + [63, 267, 62, 62, -31, -32], + [126, 267, 62, 62, -31, -32], + [189, 267, 62, 62, -31, -32], + [252, 267, 62, 62, -31, -32], + [315, 267, 62, 62, -31, -32], + [378, 267, 62, 62, -31, -32], + [441, 267, 62, 62, -31, -32], + [504, 267, 62, 62, -31, -32] + ], + [ + [567, 267, 65, 68, -33, -40], + [633, 267, 65, 68, -33, -40], + [699, 267, 65, 68, -33, -40], + [765, 267, 65, 68, -33, -40], + [831, 267, 65, 68, -33, -40], + [897, 267, 65, 68, -33, -40], + [0, 336, 65, 68, -33, -40], + [66, 336, 65, 68, -33, -40], + [132, 336, 65, 68, -33, -40], + [198, 336, 65, 68, -33, -40] + ], + [ + [264, 336, 58, 60, -30, -33], + [323, 336, 58, 60, -30, -33], + [382, 336, 58, 60, -30, -33], + [441, 336, 58, 60, -30, -33], + [500, 336, 58, 60, -30, -33], + [559, 336, 58, 60, -30, -33], + [618, 336, 58, 60, -30, -33], + [677, 336, 58, 60, -30, -33], + [736, 336, 58, 60, -30, -33], + [795, 336, 58, 60, -30, -33] + ], + [ + [854, 336, 72, 56, -41, -29], + [927, 336, 72, 56, -41, -29], + [0, 405, 72, 56, -41, -29], + [73, 405, 72, 56, -41, -29], + [146, 405, 72, 56, -41, -29], + [219, 405, 72, 56, -41, -29], + [292, 405, 72, 56, -41, -29], + [365, 405, 72, 56, -41, -29], + [438, 405, 72, 56, -41, -29], + [511, 405, 72, 56, -41, -29] + ], + [ + [584, 405, 72, 56, -29, -33], + [657, 405, 72, 56, -29, -33], + [730, 405, 72, 56, -29, -33], + [803, 405, 72, 56, -29, -33], + [876, 405, 72, 56, -29, -33], + [949, 405, 72, 56, -29, -33], + [0, 462, 72, 56, -29, -33], + [73, 462, 72, 56, -29, -33], + [146, 462, 72, 56, -29, -33], + [219, 462, 72, 56, -29, -33] + ], + [ + [292, 462, 71, 76, -31, -42], + [364, 462, 71, 76, -31, -42], + [436, 462, 71, 76, -31, -42], + [508, 462, 71, 76, -31, -42], + [580, 462, 71, 76, -31, -42], + [652, 462, 71, 76, -31, -42], + [724, 462, 71, 76, -31, -42], + [796, 462, 71, 76, -31, -42], + [868, 462, 71, 76, -31, -42], + [940, 462, 71, 76, -31, -42] + ], + [ + [0, 539, 61, 63, -28, -34], + [62, 539, 61, 63, -28, -34], + [124, 539, 61, 63, -28, -34], + [186, 539, 61, 63, -28, -34], + [248, 539, 61, 63, -28, -34], + [310, 539, 61, 63, -28, -34], + [372, 539, 61, 63, -28, -34], + [434, 539, 61, 63, -28, -34], + [496, 539, 61, 63, -28, -34], + [558, 539, 61, 63, -28, -34] + ], + [ + [620, 539, 73, 61, -29, -29], + [694, 539, 73, 61, -29, -29], + [768, 539, 73, 61, -29, -29], + [842, 539, 73, 61, -29, -29], + [916, 539, 73, 61, -29, -29], + [0, 603, 73, 61, -29, -29], + [74, 603, 73, 61, -29, -29], + [148, 603, 73, 61, -29, -29], + [222, 603, 73, 61, -29, -29], + [296, 603, 73, 61, -29, -29] + ], + [ + [370, 603, 62, 63, -34, -33], + [433, 603, 62, 63, -34, -33], + [496, 603, 62, 63, -34, -33], + [559, 603, 62, 63, -34, -33], + [622, 603, 62, 63, -34, -33], + [685, 603, 62, 63, -34, -33], + [748, 603, 62, 63, -34, -33], + [811, 603, 62, 63, -34, -33], + [874, 603, 62, 63, -34, -33], + [937, 603, 62, 63, -34, -33] + ], + [ + [0, 667, 61, 77, -32, -42], + [62, 667, 61, 77, -32, -42], + [124, 667, 61, 77, -32, -42], + [186, 667, 61, 77, -32, -42], + [248, 667, 61, 77, -32, -42], + [310, 667, 61, 77, -32, -42], + [372, 667, 61, 77, -32, -42], + [434, 667, 61, 77, -32, -42], + [496, 667, 61, 77, -32, -42], + [558, 667, 61, 77, -32, -42] + ] + ], +} + +export const TEETH_META: MissileMeta = { + name: "teeth", + celFile: "teethMissile", + width: 2048, + height: 1242, + directions: 32, + framesPerDirection: 30, + animSpeed: 16, + groups: [ + [ + [0, 0, 63, 38, -15, -51], + [64, 0, 63, 38, -15, -51], + [128, 0, 63, 38, -15, -51], + [192, 0, 63, 38, -15, -51], + [256, 0, 63, 38, -15, -51], + [320, 0, 63, 38, -15, -51], + [384, 0, 63, 38, -15, -51], + [448, 0, 63, 38, -15, -51], + [512, 0, 63, 38, -15, -51], + [576, 0, 63, 38, -15, -51], + [640, 0, 63, 38, -15, -51], + [704, 0, 63, 38, -15, -51], + [768, 0, 63, 38, -15, -51], + [832, 0, 63, 38, -15, -51], + [896, 0, 63, 38, -15, -51], + [960, 0, 63, 38, -15, -51], + [1024, 0, 63, 38, -15, -51], + [1088, 0, 63, 38, -15, -51], + [1152, 0, 63, 38, -15, -51], + [1216, 0, 63, 38, -15, -51], + [1280, 0, 63, 38, -15, -51], + [1344, 0, 63, 38, -15, -51], + [1408, 0, 63, 38, -15, -51], + [1472, 0, 63, 38, -15, -51], + [1536, 0, 63, 38, -15, -51], + [1600, 0, 63, 38, -15, -51], + [1664, 0, 63, 38, -15, -51], + [1728, 0, 63, 38, -15, -51], + [1792, 0, 63, 38, -15, -51], + [1856, 0, 63, 38, -15, -51] + ], + [ + [1920, 0, 57, 43, -14, -42], + [1978, 0, 57, 43, -14, -42], + [0, 44, 57, 43, -14, -42], + [58, 44, 57, 43, -14, -42], + [116, 44, 57, 43, -14, -42], + [174, 44, 57, 43, -14, -42], + [232, 44, 57, 43, -14, -42], + [290, 44, 57, 43, -14, -42], + [348, 44, 57, 43, -14, -42], + [406, 44, 57, 43, -14, -42], + [464, 44, 57, 43, -14, -42], + [522, 44, 57, 43, -14, -42], + [580, 44, 57, 43, -14, -42], + [638, 44, 57, 43, -14, -42], + [696, 44, 57, 43, -14, -42], + [754, 44, 57, 43, -14, -42], + [812, 44, 57, 43, -14, -42], + [870, 44, 57, 43, -14, -42], + [928, 44, 57, 43, -14, -42], + [986, 44, 57, 43, -14, -42], + [1044, 44, 57, 43, -14, -42], + [1102, 44, 57, 43, -14, -42], + [1160, 44, 57, 43, -14, -42], + [1218, 44, 57, 43, -14, -42], + [1276, 44, 57, 43, -14, -42], + [1334, 44, 57, 43, -14, -42], + [1392, 44, 57, 43, -14, -42], + [1450, 44, 57, 43, -14, -42], + [1508, 44, 57, 43, -14, -42], + [1566, 44, 57, 43, -14, -42] + ], + [ + [1624, 44, 58, 44, -44, -35], + [1683, 44, 58, 44, -44, -35], + [1742, 44, 58, 44, -44, -35], + [1801, 44, 58, 44, -44, -35], + [1860, 44, 58, 44, -44, -35], + [1919, 44, 58, 44, -44, -35], + [1978, 44, 58, 44, -44, -35], + [0, 89, 58, 44, -44, -35], + [59, 89, 58, 44, -44, -35], + [118, 89, 58, 44, -44, -35], + [177, 89, 58, 44, -44, -35], + [236, 89, 58, 44, -44, -35], + [295, 89, 58, 44, -44, -35], + [354, 89, 58, 44, -44, -35], + [413, 89, 58, 44, -44, -35], + [472, 89, 58, 44, -44, -35], + [531, 89, 58, 44, -44, -35], + [590, 89, 58, 44, -44, -35], + [649, 89, 58, 44, -44, -35], + [708, 89, 58, 44, -44, -35], + [767, 89, 58, 44, -44, -35], + [826, 89, 58, 44, -44, -35], + [885, 89, 58, 44, -44, -35], + [944, 89, 58, 44, -44, -35], + [1003, 89, 58, 44, -44, -35], + [1062, 89, 58, 44, -44, -35], + [1121, 89, 58, 44, -44, -35], + [1180, 89, 58, 44, -44, -35], + [1239, 89, 58, 44, -44, -35], + [1298, 89, 58, 44, -44, -35] + ], + [ + [1357, 89, 54, 44, -40, -56], + [1412, 89, 54, 44, -40, -56], + [1467, 89, 54, 44, -40, -56], + [1522, 89, 54, 44, -40, -56], + [1577, 89, 54, 44, -40, -56], + [1632, 89, 54, 44, -40, -56], + [1687, 89, 54, 44, -40, -56], + [1742, 89, 54, 44, -40, -56], + [1797, 89, 54, 44, -40, -56], + [1852, 89, 54, 44, -40, -56], + [1907, 89, 54, 44, -40, -56], + [1962, 89, 54, 44, -40, -56], + [0, 134, 54, 44, -40, -56], + [55, 134, 54, 44, -40, -56], + [110, 134, 54, 44, -40, -56], + [165, 134, 54, 44, -40, -56], + [220, 134, 54, 44, -40, -56], + [275, 134, 54, 44, -40, -56], + [330, 134, 54, 44, -40, -56], + [385, 134, 54, 44, -40, -56], + [440, 134, 54, 44, -40, -56], + [495, 134, 54, 44, -40, -56], + [550, 134, 54, 44, -40, -56], + [605, 134, 54, 44, -40, -56], + [660, 134, 54, 44, -40, -56], + [715, 134, 54, 44, -40, -56], + [770, 134, 54, 44, -40, -56], + [825, 134, 54, 44, -40, -56], + [880, 134, 54, 44, -40, -56], + [935, 134, 54, 44, -40, -56] + ], + [ + [990, 134, 35, 53, -19, -63], + [1026, 134, 35, 53, -19, -63], + [1062, 134, 35, 53, -19, -63], + [1098, 134, 35, 53, -19, -63], + [1134, 134, 35, 53, -19, -63], + [1170, 134, 35, 53, -19, -63], + [1206, 134, 35, 53, -19, -63], + [1242, 134, 35, 53, -19, -63], + [1278, 134, 35, 53, -19, -63], + [1314, 134, 35, 53, -19, -63], + [1350, 134, 35, 53, -19, -63], + [1386, 134, 35, 53, -19, -63], + [1422, 134, 35, 53, -19, -63], + [1458, 134, 35, 53, -19, -63], + [1494, 134, 35, 53, -19, -63], + [1530, 134, 35, 53, -19, -63], + [1566, 134, 35, 53, -19, -63], + [1602, 134, 35, 53, -19, -63], + [1638, 134, 35, 53, -19, -63], + [1674, 134, 35, 53, -19, -63], + [1710, 134, 35, 53, -19, -63], + [1746, 134, 35, 53, -19, -63], + [1782, 134, 35, 53, -19, -63], + [1818, 134, 35, 53, -19, -63], + [1854, 134, 35, 53, -19, -63], + [1890, 134, 35, 53, -19, -63], + [1926, 134, 35, 53, -19, -63], + [1962, 134, 35, 53, -19, -63], + [1998, 134, 35, 53, -19, -63], + [0, 188, 35, 53, -19, -63] + ], + [ + [36, 188, 66, 32, -10, -42], + [103, 188, 66, 32, -10, -42], + [170, 188, 66, 32, -10, -42], + [237, 188, 66, 32, -10, -42], + [304, 188, 66, 32, -10, -42], + [371, 188, 66, 32, -10, -42], + [438, 188, 66, 32, -10, -42], + [505, 188, 66, 32, -10, -42], + [572, 188, 66, 32, -10, -42], + [639, 188, 66, 32, -10, -42], + [706, 188, 66, 32, -10, -42], + [773, 188, 66, 32, -10, -42], + [840, 188, 66, 32, -10, -42], + [907, 188, 66, 32, -10, -42], + [974, 188, 66, 32, -10, -42], + [1041, 188, 66, 32, -10, -42], + [1108, 188, 66, 32, -10, -42], + [1175, 188, 66, 32, -10, -42], + [1242, 188, 66, 32, -10, -42], + [1309, 188, 66, 32, -10, -42], + [1376, 188, 66, 32, -10, -42], + [1443, 188, 66, 32, -10, -42], + [1510, 188, 66, 32, -10, -42], + [1577, 188, 66, 32, -10, -42], + [1644, 188, 66, 32, -10, -42], + [1711, 188, 66, 32, -10, -42], + [1778, 188, 66, 32, -10, -42], + [1845, 188, 66, 32, -10, -42], + [1912, 188, 66, 32, -10, -42], + [1979, 188, 66, 32, -10, -42] + ], + [ + [0, 242, 26, 53, -14, -40], + [27, 242, 26, 53, -14, -40], + [54, 242, 26, 53, -14, -40], + [81, 242, 26, 53, -14, -40], + [108, 242, 26, 53, -14, -40], + [135, 242, 26, 53, -14, -40], + [162, 242, 26, 53, -14, -40], + [189, 242, 26, 53, -14, -40], + [216, 242, 26, 53, -14, -40], + [243, 242, 26, 53, -14, -40], + [270, 242, 26, 53, -14, -40], + [297, 242, 26, 53, -14, -40], + [324, 242, 26, 53, -14, -40], + [351, 242, 26, 53, -14, -40], + [378, 242, 26, 53, -14, -40], + [405, 242, 26, 53, -14, -40], + [432, 242, 26, 53, -14, -40], + [459, 242, 26, 53, -14, -40], + [486, 242, 26, 53, -14, -40], + [513, 242, 26, 53, -14, -40], + [540, 242, 26, 53, -14, -40], + [567, 242, 26, 53, -14, -40], + [594, 242, 26, 53, -14, -40], + [621, 242, 26, 53, -14, -40], + [648, 242, 26, 53, -14, -40], + [675, 242, 26, 53, -14, -40], + [702, 242, 26, 53, -14, -40], + [729, 242, 26, 53, -14, -40], + [756, 242, 26, 53, -14, -40], + [783, 242, 26, 53, -14, -40] + ], + [ + [810, 242, 68, 30, -56, -40], + [879, 242, 68, 30, -56, -40], + [948, 242, 68, 30, -56, -40], + [1017, 242, 68, 30, -56, -40], + [1086, 242, 68, 30, -56, -40], + [1155, 242, 68, 30, -56, -40], + [1224, 242, 68, 30, -56, -40], + [1293, 242, 68, 30, -56, -40], + [1362, 242, 68, 30, -56, -40], + [1431, 242, 68, 30, -56, -40], + [1500, 242, 68, 30, -56, -40], + [1569, 242, 68, 30, -56, -40], + [1638, 242, 68, 30, -56, -40], + [1707, 242, 68, 30, -56, -40], + [1776, 242, 68, 30, -56, -40], + [1845, 242, 68, 30, -56, -40], + [1914, 242, 68, 30, -56, -40], + [0, 296, 68, 30, -56, -40], + [69, 296, 68, 30, -56, -40], + [138, 296, 68, 30, -56, -40], + [207, 296, 68, 30, -56, -40], + [276, 296, 68, 30, -56, -40], + [345, 296, 68, 30, -56, -40], + [414, 296, 68, 30, -56, -40], + [483, 296, 68, 30, -56, -40], + [552, 296, 68, 30, -56, -40], + [621, 296, 68, 30, -56, -40], + [690, 296, 68, 30, -56, -40], + [759, 296, 68, 30, -56, -40], + [828, 296, 68, 30, -56, -40] + ], + [ + [897, 296, 38, 49, -9, -63], + [936, 296, 38, 49, -9, -63], + [975, 296, 38, 49, -9, -63], + [1014, 296, 38, 49, -9, -63], + [1053, 296, 38, 49, -9, -63], + [1092, 296, 38, 49, -9, -63], + [1131, 296, 38, 49, -9, -63], + [1170, 296, 38, 49, -9, -63], + [1209, 296, 38, 49, -9, -63], + [1248, 296, 38, 49, -9, -63], + [1287, 296, 38, 49, -9, -63], + [1326, 296, 38, 49, -9, -63], + [1365, 296, 38, 49, -9, -63], + [1404, 296, 38, 49, -9, -63], + [1443, 296, 38, 49, -9, -63], + [1482, 296, 38, 49, -9, -63], + [1521, 296, 38, 49, -9, -63], + [1560, 296, 38, 49, -9, -63], + [1599, 296, 38, 49, -9, -63], + [1638, 296, 38, 49, -9, -63], + [1677, 296, 38, 49, -9, -63], + [1716, 296, 38, 49, -9, -63], + [1755, 296, 38, 49, -9, -63], + [1794, 296, 38, 49, -9, -63], + [1833, 296, 38, 49, -9, -63], + [1872, 296, 38, 49, -9, -63], + [1911, 296, 38, 49, -9, -63], + [1950, 296, 38, 49, -9, -63], + [1989, 296, 38, 49, -9, -63], + [0, 346, 38, 49, -9, -63] + ], + [ + [39, 346, 66, 30, -12, -42], + [106, 346, 66, 30, -12, -42], + [173, 346, 66, 30, -12, -42], + [240, 346, 66, 30, -12, -42], + [307, 346, 66, 30, -12, -42], + [374, 346, 66, 30, -12, -42], + [441, 346, 66, 30, -12, -42], + [508, 346, 66, 30, -12, -42], + [575, 346, 66, 30, -12, -42], + [642, 346, 66, 30, -12, -42], + [709, 346, 66, 30, -12, -42], + [776, 346, 66, 30, -12, -42], + [843, 346, 66, 30, -12, -42], + [910, 346, 66, 30, -12, -42], + [977, 346, 66, 30, -12, -42], + [1044, 346, 66, 30, -12, -42], + [1111, 346, 66, 30, -12, -42], + [1178, 346, 66, 30, -12, -42], + [1245, 346, 66, 30, -12, -42], + [1312, 346, 66, 30, -12, -42], + [1379, 346, 66, 30, -12, -42], + [1446, 346, 66, 30, -12, -42], + [1513, 346, 66, 30, -12, -42], + [1580, 346, 66, 30, -12, -42], + [1647, 346, 66, 30, -12, -42], + [1714, 346, 66, 30, -12, -42], + [1781, 346, 66, 30, -12, -42], + [1848, 346, 66, 30, -12, -42], + [1915, 346, 66, 30, -12, -42], + [1982, 346, 66, 30, -12, -42] + ], + [ + [0, 396, 66, 34, -13, -40], + [67, 396, 66, 34, -13, -40], + [134, 396, 66, 34, -13, -40], + [201, 396, 66, 34, -13, -40], + [268, 396, 66, 34, -13, -40], + [335, 396, 66, 34, -13, -40], + [402, 396, 66, 34, -13, -40], + [469, 396, 66, 34, -13, -40], + [536, 396, 66, 34, -13, -40], + [603, 396, 66, 34, -13, -40], + [670, 396, 66, 34, -13, -40], + [737, 396, 66, 34, -13, -40], + [804, 396, 66, 34, -13, -40], + [871, 396, 66, 34, -13, -40], + [938, 396, 66, 34, -13, -40], + [1005, 396, 66, 34, -13, -40], + [1072, 396, 66, 34, -13, -40], + [1139, 396, 66, 34, -13, -40], + [1206, 396, 66, 34, -13, -40], + [1273, 396, 66, 34, -13, -40], + [1340, 396, 66, 34, -13, -40], + [1407, 396, 66, 34, -13, -40], + [1474, 396, 66, 34, -13, -40], + [1541, 396, 66, 34, -13, -40], + [1608, 396, 66, 34, -13, -40], + [1675, 396, 66, 34, -13, -40], + [1742, 396, 66, 34, -13, -40], + [1809, 396, 66, 34, -13, -40], + [1876, 396, 66, 34, -13, -40], + [1943, 396, 66, 34, -13, -40] + ], + [ + [0, 431, 45, 47, -15, -42], + [46, 431, 45, 47, -15, -42], + [92, 431, 45, 47, -15, -42], + [138, 431, 45, 47, -15, -42], + [184, 431, 45, 47, -15, -42], + [230, 431, 45, 47, -15, -42], + [276, 431, 45, 47, -15, -42], + [322, 431, 45, 47, -15, -42], + [368, 431, 45, 47, -15, -42], + [414, 431, 45, 47, -15, -42], + [460, 431, 45, 47, -15, -42], + [506, 431, 45, 47, -15, -42], + [552, 431, 45, 47, -15, -42], + [598, 431, 45, 47, -15, -42], + [644, 431, 45, 47, -15, -42], + [690, 431, 45, 47, -15, -42], + [736, 431, 45, 47, -15, -42], + [782, 431, 45, 47, -15, -42], + [828, 431, 45, 47, -15, -42], + [874, 431, 45, 47, -15, -42], + [920, 431, 45, 47, -15, -42], + [966, 431, 45, 47, -15, -42], + [1012, 431, 45, 47, -15, -42], + [1058, 431, 45, 47, -15, -42], + [1104, 431, 45, 47, -15, -42], + [1150, 431, 45, 47, -15, -42], + [1196, 431, 45, 47, -15, -42], + [1242, 431, 45, 47, -15, -42], + [1288, 431, 45, 47, -15, -42], + [1334, 431, 45, 47, -15, -42] + ], + [ + [1380, 431, 41, 54, -29, -44], + [1422, 431, 41, 54, -29, -44], + [1464, 431, 41, 54, -29, -44], + [1506, 431, 41, 54, -29, -44], + [1548, 431, 41, 54, -29, -44], + [1590, 431, 41, 54, -29, -44], + [1632, 431, 41, 54, -29, -44], + [1674, 431, 41, 54, -29, -44], + [1716, 431, 41, 54, -29, -44], + [1758, 431, 41, 54, -29, -44], + [1800, 431, 41, 54, -29, -44], + [1842, 431, 41, 54, -29, -44], + [1884, 431, 41, 54, -29, -44], + [1926, 431, 41, 54, -29, -44], + [1968, 431, 41, 54, -29, -44], + [0, 486, 41, 54, -29, -44], + [42, 486, 41, 54, -29, -44], + [84, 486, 41, 54, -29, -44], + [126, 486, 41, 54, -29, -44], + [168, 486, 41, 54, -29, -44], + [210, 486, 41, 54, -29, -44], + [252, 486, 41, 54, -29, -44], + [294, 486, 41, 54, -29, -44], + [336, 486, 41, 54, -29, -44], + [378, 486, 41, 54, -29, -44], + [420, 486, 41, 54, -29, -44], + [462, 486, 41, 54, -29, -44], + [504, 486, 41, 54, -29, -44], + [546, 486, 41, 54, -29, -44], + [588, 486, 41, 54, -29, -44] + ], + [ + [630, 486, 67, 34, -53, -38], + [698, 486, 67, 34, -53, -38], + [766, 486, 67, 34, -53, -38], + [834, 486, 67, 34, -53, -38], + [902, 486, 67, 34, -53, -38], + [970, 486, 67, 34, -53, -38], + [1038, 486, 67, 34, -53, -38], + [1106, 486, 67, 34, -53, -38], + [1174, 486, 67, 34, -53, -38], + [1242, 486, 67, 34, -53, -38], + [1310, 486, 67, 34, -53, -38], + [1378, 486, 67, 34, -53, -38], + [1446, 486, 67, 34, -53, -38], + [1514, 486, 67, 34, -53, -38], + [1582, 486, 67, 34, -53, -38], + [1650, 486, 67, 34, -53, -38], + [1718, 486, 67, 34, -53, -38], + [1786, 486, 67, 34, -53, -38], + [1854, 486, 67, 34, -53, -38], + [1922, 486, 67, 34, -53, -38], + [0, 541, 67, 34, -53, -38], + [68, 541, 67, 34, -53, -38], + [136, 541, 67, 34, -53, -38], + [204, 541, 67, 34, -53, -38], + [272, 541, 67, 34, -53, -38], + [340, 541, 67, 34, -53, -38], + [408, 541, 67, 34, -53, -38], + [476, 541, 67, 34, -53, -38], + [544, 541, 67, 34, -53, -38], + [612, 541, 67, 34, -53, -38] + ], + [ + [680, 541, 65, 42, -53, -47], + [746, 541, 65, 42, -53, -47], + [812, 541, 65, 42, -53, -47], + [878, 541, 65, 42, -53, -47], + [944, 541, 65, 42, -53, -47], + [1010, 541, 65, 42, -53, -47], + [1076, 541, 65, 42, -53, -47], + [1142, 541, 65, 42, -53, -47], + [1208, 541, 65, 42, -53, -47], + [1274, 541, 65, 42, -53, -47], + [1340, 541, 65, 42, -53, -47], + [1406, 541, 65, 42, -53, -47], + [1472, 541, 65, 42, -53, -47], + [1538, 541, 65, 42, -53, -47], + [1604, 541, 65, 42, -53, -47], + [1670, 541, 65, 42, -53, -47], + [1736, 541, 65, 42, -53, -47], + [1802, 541, 65, 42, -53, -47], + [1868, 541, 65, 42, -53, -47], + [1934, 541, 65, 42, -53, -47], + [0, 584, 65, 42, -53, -47], + [66, 584, 65, 42, -53, -47], + [132, 584, 65, 42, -53, -47], + [198, 584, 65, 42, -53, -47], + [264, 584, 65, 42, -53, -47], + [330, 584, 65, 42, -53, -47], + [396, 584, 65, 42, -53, -47], + [462, 584, 65, 42, -53, -47], + [528, 584, 65, 42, -53, -47], + [594, 584, 65, 42, -53, -47] + ], + [ + [660, 584, 44, 53, -30, -57], + [705, 584, 44, 53, -30, -57], + [750, 584, 44, 53, -30, -57], + [795, 584, 44, 53, -30, -57], + [840, 584, 44, 53, -30, -57], + [885, 584, 44, 53, -30, -57], + [930, 584, 44, 53, -30, -57], + [975, 584, 44, 53, -30, -57], + [1020, 584, 44, 53, -30, -57], + [1065, 584, 44, 53, -30, -57], + [1110, 584, 44, 53, -30, -57], + [1155, 584, 44, 53, -30, -57], + [1200, 584, 44, 53, -30, -57], + [1245, 584, 44, 53, -30, -57], + [1290, 584, 44, 53, -30, -57], + [1335, 584, 44, 53, -30, -57], + [1380, 584, 44, 53, -30, -57], + [1425, 584, 44, 53, -30, -57], + [1470, 584, 44, 53, -30, -57], + [1515, 584, 44, 53, -30, -57], + [1560, 584, 44, 53, -30, -57], + [1605, 584, 44, 53, -30, -57], + [1650, 584, 44, 53, -30, -57], + [1695, 584, 44, 53, -30, -57], + [1740, 584, 44, 53, -30, -57], + [1785, 584, 44, 53, -30, -57], + [1830, 584, 44, 53, -30, -57], + [1875, 584, 44, 53, -30, -57], + [1920, 584, 44, 53, -30, -57], + [1965, 584, 44, 53, -30, -57] + ], + [ + [2010, 584, 32, 50, -14, -60], + [0, 638, 32, 50, -14, -60], + [33, 638, 32, 50, -14, -60], + [66, 638, 32, 50, -14, -60], + [99, 638, 32, 50, -14, -60], + [132, 638, 32, 50, -14, -60], + [165, 638, 32, 50, -14, -60], + [198, 638, 32, 50, -14, -60], + [231, 638, 32, 50, -14, -60], + [264, 638, 32, 50, -14, -60], + [297, 638, 32, 50, -14, -60], + [330, 638, 32, 50, -14, -60], + [363, 638, 32, 50, -14, -60], + [396, 638, 32, 50, -14, -60], + [429, 638, 32, 50, -14, -60], + [462, 638, 32, 50, -14, -60], + [495, 638, 32, 50, -14, -60], + [528, 638, 32, 50, -14, -60], + [561, 638, 32, 50, -14, -60], + [594, 638, 32, 50, -14, -60], + [627, 638, 32, 50, -14, -60], + [660, 638, 32, 50, -14, -60], + [693, 638, 32, 50, -14, -60], + [726, 638, 32, 50, -14, -60], + [759, 638, 32, 50, -14, -60], + [792, 638, 32, 50, -14, -60], + [825, 638, 32, 50, -14, -60], + [858, 638, 32, 50, -14, -60], + [891, 638, 32, 50, -14, -60], + [924, 638, 32, 50, -14, -60] + ], + [ + [957, 638, 58, 41, -16, -52], + [1016, 638, 58, 41, -16, -52], + [1075, 638, 58, 41, -16, -52], + [1134, 638, 58, 41, -16, -52], + [1193, 638, 58, 41, -16, -52], + [1252, 638, 58, 41, -16, -52], + [1311, 638, 58, 41, -16, -52], + [1370, 638, 58, 41, -16, -52], + [1429, 638, 58, 41, -16, -52], + [1488, 638, 58, 41, -16, -52], + [1547, 638, 58, 41, -16, -52], + [1606, 638, 58, 41, -16, -52], + [1665, 638, 58, 41, -16, -52], + [1724, 638, 58, 41, -16, -52], + [1783, 638, 58, 41, -16, -52], + [1842, 638, 58, 41, -16, -52], + [1901, 638, 58, 41, -16, -52], + [1960, 638, 58, 41, -16, -52], + [0, 689, 58, 41, -16, -52], + [59, 689, 58, 41, -16, -52], + [118, 689, 58, 41, -16, -52], + [177, 689, 58, 41, -16, -52], + [236, 689, 58, 41, -16, -52], + [295, 689, 58, 41, -16, -52], + [354, 689, 58, 41, -16, -52], + [413, 689, 58, 41, -16, -52], + [472, 689, 58, 41, -16, -52], + [531, 689, 58, 41, -16, -52], + [590, 689, 58, 41, -16, -52], + [649, 689, 58, 41, -16, -52] + ], + [ + [708, 689, 63, 37, -15, -49], + [772, 689, 63, 37, -15, -49], + [836, 689, 63, 37, -15, -49], + [900, 689, 63, 37, -15, -49], + [964, 689, 63, 37, -15, -49], + [1028, 689, 63, 37, -15, -49], + [1092, 689, 63, 37, -15, -49], + [1156, 689, 63, 37, -15, -49], + [1220, 689, 63, 37, -15, -49], + [1284, 689, 63, 37, -15, -49], + [1348, 689, 63, 37, -15, -49], + [1412, 689, 63, 37, -15, -49], + [1476, 689, 63, 37, -15, -49], + [1540, 689, 63, 37, -15, -49], + [1604, 689, 63, 37, -15, -49], + [1668, 689, 63, 37, -15, -49], + [1732, 689, 63, 37, -15, -49], + [1796, 689, 63, 37, -15, -49], + [1860, 689, 63, 37, -15, -49], + [1924, 689, 63, 37, -15, -49], + [0, 731, 63, 37, -15, -49], + [64, 731, 63, 37, -15, -49], + [128, 731, 63, 37, -15, -49], + [192, 731, 63, 37, -15, -49], + [256, 731, 63, 37, -15, -49], + [320, 731, 63, 37, -15, -49], + [384, 731, 63, 37, -15, -49], + [448, 731, 63, 37, -15, -49], + [512, 731, 63, 37, -15, -49], + [576, 731, 63, 37, -15, -49] + ], + [ + [640, 731, 68, 35, -14, -44], + [709, 731, 68, 35, -14, -44], + [778, 731, 68, 35, -14, -44], + [847, 731, 68, 35, -14, -44], + [916, 731, 68, 35, -14, -44], + [985, 731, 68, 35, -14, -44], + [1054, 731, 68, 35, -14, -44], + [1123, 731, 68, 35, -14, -44], + [1192, 731, 68, 35, -14, -44], + [1261, 731, 68, 35, -14, -44], + [1330, 731, 68, 35, -14, -44], + [1399, 731, 68, 35, -14, -44], + [1468, 731, 68, 35, -14, -44], + [1537, 731, 68, 35, -14, -44], + [1606, 731, 68, 35, -14, -44], + [1675, 731, 68, 35, -14, -44], + [1744, 731, 68, 35, -14, -44], + [1813, 731, 68, 35, -14, -44], + [1882, 731, 68, 35, -14, -44], + [1951, 731, 68, 35, -14, -44], + [0, 769, 68, 35, -14, -44], + [69, 769, 68, 35, -14, -44], + [138, 769, 68, 35, -14, -44], + [207, 769, 68, 35, -14, -44], + [276, 769, 68, 35, -14, -44], + [345, 769, 68, 35, -14, -44], + [414, 769, 68, 35, -14, -44], + [483, 769, 68, 35, -14, -44], + [552, 769, 68, 35, -14, -44], + [621, 769, 68, 35, -14, -44] + ], + [ + [690, 769, 66, 27, -11, -36], + [757, 769, 66, 27, -11, -36], + [824, 769, 66, 27, -11, -36], + [891, 769, 66, 27, -11, -36], + [958, 769, 66, 27, -11, -36], + [1025, 769, 66, 27, -11, -36], + [1092, 769, 66, 27, -11, -36], + [1159, 769, 66, 27, -11, -36], + [1226, 769, 66, 27, -11, -36], + [1293, 769, 66, 27, -11, -36], + [1360, 769, 66, 27, -11, -36], + [1427, 769, 66, 27, -11, -36], + [1494, 769, 66, 27, -11, -36], + [1561, 769, 66, 27, -11, -36], + [1628, 769, 66, 27, -11, -36], + [1695, 769, 66, 27, -11, -36], + [1762, 769, 66, 27, -11, -36], + [1829, 769, 66, 27, -11, -36], + [1896, 769, 66, 27, -11, -36], + [1963, 769, 66, 27, -11, -36], + [0, 805, 66, 27, -11, -36], + [67, 805, 66, 27, -11, -36], + [134, 805, 66, 27, -11, -36], + [201, 805, 66, 27, -11, -36], + [268, 805, 66, 27, -11, -36], + [335, 805, 66, 27, -11, -36], + [402, 805, 66, 27, -11, -36], + [469, 805, 66, 27, -11, -36], + [536, 805, 66, 27, -11, -36], + [603, 805, 66, 27, -11, -36] + ], + [ + [670, 805, 64, 35, -14, -42], + [735, 805, 64, 35, -14, -42], + [800, 805, 64, 35, -14, -42], + [865, 805, 64, 35, -14, -42], + [930, 805, 64, 35, -14, -42], + [995, 805, 64, 35, -14, -42], + [1060, 805, 64, 35, -14, -42], + [1125, 805, 64, 35, -14, -42], + [1190, 805, 64, 35, -14, -42], + [1255, 805, 64, 35, -14, -42], + [1320, 805, 64, 35, -14, -42], + [1385, 805, 64, 35, -14, -42], + [1450, 805, 64, 35, -14, -42], + [1515, 805, 64, 35, -14, -42], + [1580, 805, 64, 35, -14, -42], + [1645, 805, 64, 35, -14, -42], + [1710, 805, 64, 35, -14, -42], + [1775, 805, 64, 35, -14, -42], + [1840, 805, 64, 35, -14, -42], + [1905, 805, 64, 35, -14, -42], + [1970, 805, 64, 35, -14, -42], + [0, 841, 64, 35, -14, -42], + [65, 841, 64, 35, -14, -42], + [130, 841, 64, 35, -14, -42], + [195, 841, 64, 35, -14, -42], + [260, 841, 64, 35, -14, -42], + [325, 841, 64, 35, -14, -42], + [390, 841, 64, 35, -14, -42], + [455, 841, 64, 35, -14, -42], + [520, 841, 64, 35, -14, -42] + ], + [ + [585, 841, 49, 48, -16, -40], + [635, 841, 49, 48, -16, -40], + [685, 841, 49, 48, -16, -40], + [735, 841, 49, 48, -16, -40], + [785, 841, 49, 48, -16, -40], + [835, 841, 49, 48, -16, -40], + [885, 841, 49, 48, -16, -40], + [935, 841, 49, 48, -16, -40], + [985, 841, 49, 48, -16, -40], + [1035, 841, 49, 48, -16, -40], + [1085, 841, 49, 48, -16, -40], + [1135, 841, 49, 48, -16, -40], + [1185, 841, 49, 48, -16, -40], + [1235, 841, 49, 48, -16, -40], + [1285, 841, 49, 48, -16, -40], + [1335, 841, 49, 48, -16, -40], + [1385, 841, 49, 48, -16, -40], + [1435, 841, 49, 48, -16, -40], + [1485, 841, 49, 48, -16, -40], + [1535, 841, 49, 48, -16, -40], + [1585, 841, 49, 48, -16, -40], + [1635, 841, 49, 48, -16, -40], + [1685, 841, 49, 48, -16, -40], + [1735, 841, 49, 48, -16, -40], + [1785, 841, 49, 48, -16, -40], + [1835, 841, 49, 48, -16, -40], + [1885, 841, 49, 48, -16, -40], + [1935, 841, 49, 48, -16, -40], + [1985, 841, 49, 48, -16, -40], + [0, 890, 49, 48, -16, -40] + ], + [ + [50, 890, 35, 46, -13, -42], + [86, 890, 35, 46, -13, -42], + [122, 890, 35, 46, -13, -42], + [158, 890, 35, 46, -13, -42], + [194, 890, 35, 46, -13, -42], + [230, 890, 35, 46, -13, -42], + [266, 890, 35, 46, -13, -42], + [302, 890, 35, 46, -13, -42], + [338, 890, 35, 46, -13, -42], + [374, 890, 35, 46, -13, -42], + [410, 890, 35, 46, -13, -42], + [446, 890, 35, 46, -13, -42], + [482, 890, 35, 46, -13, -42], + [518, 890, 35, 46, -13, -42], + [554, 890, 35, 46, -13, -42], + [590, 890, 35, 46, -13, -42], + [626, 890, 35, 46, -13, -42], + [662, 890, 35, 46, -13, -42], + [698, 890, 35, 46, -13, -42], + [734, 890, 35, 46, -13, -42], + [770, 890, 35, 46, -13, -42], + [806, 890, 35, 46, -13, -42], + [842, 890, 35, 46, -13, -42], + [878, 890, 35, 46, -13, -42], + [914, 890, 35, 46, -13, -42], + [950, 890, 35, 46, -13, -42], + [986, 890, 35, 46, -13, -42], + [1022, 890, 35, 46, -13, -42], + [1058, 890, 35, 46, -13, -42], + [1094, 890, 35, 46, -13, -42] + ], + [ + [1130, 890, 32, 48, -22, -39], + [1163, 890, 32, 48, -22, -39], + [1196, 890, 32, 48, -22, -39], + [1229, 890, 32, 48, -22, -39], + [1262, 890, 32, 48, -22, -39], + [1295, 890, 32, 48, -22, -39], + [1328, 890, 32, 48, -22, -39], + [1361, 890, 32, 48, -22, -39], + [1394, 890, 32, 48, -22, -39], + [1427, 890, 32, 48, -22, -39], + [1460, 890, 32, 48, -22, -39], + [1493, 890, 32, 48, -22, -39], + [1526, 890, 32, 48, -22, -39], + [1559, 890, 32, 48, -22, -39], + [1592, 890, 32, 48, -22, -39], + [1625, 890, 32, 48, -22, -39], + [1658, 890, 32, 48, -22, -39], + [1691, 890, 32, 48, -22, -39], + [1724, 890, 32, 48, -22, -39], + [1757, 890, 32, 48, -22, -39], + [1790, 890, 32, 48, -22, -39], + [1823, 890, 32, 48, -22, -39], + [1856, 890, 32, 48, -22, -39], + [1889, 890, 32, 48, -22, -39], + [1922, 890, 32, 48, -22, -39], + [1955, 890, 32, 48, -22, -39], + [1988, 890, 32, 48, -22, -39], + [0, 939, 32, 48, -22, -39], + [33, 939, 32, 48, -22, -39], + [66, 939, 32, 48, -22, -39] + ], + [ + [99, 939, 59, 47, -41, -40], + [159, 939, 59, 47, -41, -40], + [219, 939, 59, 47, -41, -40], + [279, 939, 59, 47, -41, -40], + [339, 939, 59, 47, -41, -40], + [399, 939, 59, 47, -41, -40], + [459, 939, 59, 47, -41, -40], + [519, 939, 59, 47, -41, -40], + [579, 939, 59, 47, -41, -40], + [639, 939, 59, 47, -41, -40], + [699, 939, 59, 47, -41, -40], + [759, 939, 59, 47, -41, -40], + [819, 939, 59, 47, -41, -40], + [879, 939, 59, 47, -41, -40], + [939, 939, 59, 47, -41, -40], + [999, 939, 59, 47, -41, -40], + [1059, 939, 59, 47, -41, -40], + [1119, 939, 59, 47, -41, -40], + [1179, 939, 59, 47, -41, -40], + [1239, 939, 59, 47, -41, -40], + [1299, 939, 59, 47, -41, -40], + [1359, 939, 59, 47, -41, -40], + [1419, 939, 59, 47, -41, -40], + [1479, 939, 59, 47, -41, -40], + [1539, 939, 59, 47, -41, -40], + [1599, 939, 59, 47, -41, -40], + [1659, 939, 59, 47, -41, -40], + [1719, 939, 59, 47, -41, -40], + [1779, 939, 59, 47, -41, -40], + [1839, 939, 59, 47, -41, -40] + ], + [ + [1899, 939, 66, 35, -51, -38], + [1966, 939, 66, 35, -51, -38], + [0, 988, 66, 35, -51, -38], + [67, 988, 66, 35, -51, -38], + [134, 988, 66, 35, -51, -38], + [201, 988, 66, 35, -51, -38], + [268, 988, 66, 35, -51, -38], + [335, 988, 66, 35, -51, -38], + [402, 988, 66, 35, -51, -38], + [469, 988, 66, 35, -51, -38], + [536, 988, 66, 35, -51, -38], + [603, 988, 66, 35, -51, -38], + [670, 988, 66, 35, -51, -38], + [737, 988, 66, 35, -51, -38], + [804, 988, 66, 35, -51, -38], + [871, 988, 66, 35, -51, -38], + [938, 988, 66, 35, -51, -38], + [1005, 988, 66, 35, -51, -38], + [1072, 988, 66, 35, -51, -38], + [1139, 988, 66, 35, -51, -38], + [1206, 988, 66, 35, -51, -38], + [1273, 988, 66, 35, -51, -38], + [1340, 988, 66, 35, -51, -38], + [1407, 988, 66, 35, -51, -38], + [1474, 988, 66, 35, -51, -38], + [1541, 988, 66, 35, -51, -38], + [1608, 988, 66, 35, -51, -38], + [1675, 988, 66, 35, -51, -38], + [1742, 988, 66, 35, -51, -38], + [1809, 988, 66, 35, -51, -38] + ], + [ + [1876, 988, 69, 32, -56, -38], + [1946, 988, 69, 32, -56, -38], + [0, 1024, 69, 32, -56, -38], + [70, 1024, 69, 32, -56, -38], + [140, 1024, 69, 32, -56, -38], + [210, 1024, 69, 32, -56, -38], + [280, 1024, 69, 32, -56, -38], + [350, 1024, 69, 32, -56, -38], + [420, 1024, 69, 32, -56, -38], + [490, 1024, 69, 32, -56, -38], + [560, 1024, 69, 32, -56, -38], + [630, 1024, 69, 32, -56, -38], + [700, 1024, 69, 32, -56, -38], + [770, 1024, 69, 32, -56, -38], + [840, 1024, 69, 32, -56, -38], + [910, 1024, 69, 32, -56, -38], + [980, 1024, 69, 32, -56, -38], + [1050, 1024, 69, 32, -56, -38], + [1120, 1024, 69, 32, -56, -38], + [1190, 1024, 69, 32, -56, -38], + [1260, 1024, 69, 32, -56, -38], + [1330, 1024, 69, 32, -56, -38], + [1400, 1024, 69, 32, -56, -38], + [1470, 1024, 69, 32, -56, -38], + [1540, 1024, 69, 32, -56, -38], + [1610, 1024, 69, 32, -56, -38], + [1680, 1024, 69, 32, -56, -38], + [1750, 1024, 69, 32, -56, -38], + [1820, 1024, 69, 32, -56, -38], + [1890, 1024, 69, 32, -56, -38] + ], + [ + [1960, 1024, 67, 29, -56, -38], + [0, 1057, 67, 29, -56, -38], + [68, 1057, 67, 29, -56, -38], + [136, 1057, 67, 29, -56, -38], + [204, 1057, 67, 29, -56, -38], + [272, 1057, 67, 29, -56, -38], + [340, 1057, 67, 29, -56, -38], + [408, 1057, 67, 29, -56, -38], + [476, 1057, 67, 29, -56, -38], + [544, 1057, 67, 29, -56, -38], + [612, 1057, 67, 29, -56, -38], + [680, 1057, 67, 29, -56, -38], + [748, 1057, 67, 29, -56, -38], + [816, 1057, 67, 29, -56, -38], + [884, 1057, 67, 29, -56, -38], + [952, 1057, 67, 29, -56, -38], + [1020, 1057, 67, 29, -56, -38], + [1088, 1057, 67, 29, -56, -38], + [1156, 1057, 67, 29, -56, -38], + [1224, 1057, 67, 29, -56, -38], + [1292, 1057, 67, 29, -56, -38], + [1360, 1057, 67, 29, -56, -38], + [1428, 1057, 67, 29, -56, -38], + [1496, 1057, 67, 29, -56, -38], + [1564, 1057, 67, 29, -56, -38], + [1632, 1057, 67, 29, -56, -38], + [1700, 1057, 67, 29, -56, -38], + [1768, 1057, 67, 29, -56, -38], + [1836, 1057, 67, 29, -56, -38], + [1904, 1057, 67, 29, -56, -38] + ], + [ + [1972, 1057, 59, 38, -43, -48], + [0, 1096, 59, 38, -43, -48], + [60, 1096, 59, 38, -43, -48], + [120, 1096, 59, 38, -43, -48], + [180, 1096, 59, 38, -43, -48], + [240, 1096, 59, 38, -43, -48], + [300, 1096, 59, 38, -43, -48], + [360, 1096, 59, 38, -43, -48], + [420, 1096, 59, 38, -43, -48], + [480, 1096, 59, 38, -43, -48], + [540, 1096, 59, 38, -43, -48], + [600, 1096, 59, 38, -43, -48], + [660, 1096, 59, 38, -43, -48], + [720, 1096, 59, 38, -43, -48], + [780, 1096, 59, 38, -43, -48], + [840, 1096, 59, 38, -43, -48], + [900, 1096, 59, 38, -43, -48], + [960, 1096, 59, 38, -43, -48], + [1020, 1096, 59, 38, -43, -48], + [1080, 1096, 59, 38, -43, -48], + [1140, 1096, 59, 38, -43, -48], + [1200, 1096, 59, 38, -43, -48], + [1260, 1096, 59, 38, -43, -48], + [1320, 1096, 59, 38, -43, -48], + [1380, 1096, 59, 38, -43, -48], + [1440, 1096, 59, 38, -43, -48], + [1500, 1096, 59, 38, -43, -48], + [1560, 1096, 59, 38, -43, -48], + [1620, 1096, 59, 38, -43, -48], + [1680, 1096, 59, 38, -43, -48] + ], + [ + [1740, 1096, 51, 49, -32, -59], + [1792, 1096, 51, 49, -32, -59], + [1844, 1096, 51, 49, -32, -59], + [1896, 1096, 51, 49, -32, -59], + [1948, 1096, 51, 49, -32, -59], + [0, 1146, 51, 49, -32, -59], + [52, 1146, 51, 49, -32, -59], + [104, 1146, 51, 49, -32, -59], + [156, 1146, 51, 49, -32, -59], + [208, 1146, 51, 49, -32, -59], + [260, 1146, 51, 49, -32, -59], + [312, 1146, 51, 49, -32, -59], + [364, 1146, 51, 49, -32, -59], + [416, 1146, 51, 49, -32, -59], + [468, 1146, 51, 49, -32, -59], + [520, 1146, 51, 49, -32, -59], + [572, 1146, 51, 49, -32, -59], + [624, 1146, 51, 49, -32, -59], + [676, 1146, 51, 49, -32, -59], + [728, 1146, 51, 49, -32, -59], + [780, 1146, 51, 49, -32, -59], + [832, 1146, 51, 49, -32, -59], + [884, 1146, 51, 49, -32, -59], + [936, 1146, 51, 49, -32, -59], + [988, 1146, 51, 49, -32, -59], + [1040, 1146, 51, 49, -32, -59], + [1092, 1146, 51, 49, -32, -59], + [1144, 1146, 51, 49, -32, -59], + [1196, 1146, 51, 49, -32, -59], + [1248, 1146, 51, 49, -32, -59] + ], + [ + [1300, 1146, 36, 46, -24, -57], + [1337, 1146, 36, 46, -24, -57], + [1374, 1146, 36, 46, -24, -57], + [1411, 1146, 36, 46, -24, -57], + [1448, 1146, 36, 46, -24, -57], + [1485, 1146, 36, 46, -24, -57], + [1522, 1146, 36, 46, -24, -57], + [1559, 1146, 36, 46, -24, -57], + [1596, 1146, 36, 46, -24, -57], + [1633, 1146, 36, 46, -24, -57], + [1670, 1146, 36, 46, -24, -57], + [1707, 1146, 36, 46, -24, -57], + [1744, 1146, 36, 46, -24, -57], + [1781, 1146, 36, 46, -24, -57], + [1818, 1146, 36, 46, -24, -57], + [1855, 1146, 36, 46, -24, -57], + [1892, 1146, 36, 46, -24, -57], + [1929, 1146, 36, 46, -24, -57], + [1966, 1146, 36, 46, -24, -57], + [2003, 1146, 36, 46, -24, -57], + [0, 1196, 36, 46, -24, -57], + [37, 1196, 36, 46, -24, -57], + [74, 1196, 36, 46, -24, -57], + [111, 1196, 36, 46, -24, -57], + [148, 1196, 36, 46, -24, -57], + [185, 1196, 36, 46, -24, -57], + [222, 1196, 36, 46, -24, -57], + [259, 1196, 36, 46, -24, -57], + [296, 1196, 36, 46, -24, -57], + [333, 1196, 36, 46, -24, -57] + ] + ], +} + +export const TEETHEXPLODE_META: MissileMeta = { + name: "teethexplode", + celFile: "teethexplode", + width: 512, + height: 427, + directions: 1, + framesPerDirection: 13, + animSpeed: 16, + groups: [ + [ + [0, 0, 105, 106, -52, -100], + [106, 0, 105, 106, -52, -100], + [212, 0, 105, 106, -52, -100], + [318, 0, 105, 106, -52, -100], + [0, 107, 105, 106, -52, -100], + [106, 107, 105, 106, -52, -100], + [212, 107, 105, 106, -52, -100], + [318, 107, 105, 106, -52, -100], + [0, 214, 105, 106, -52, -100], + [106, 214, 105, 106, -52, -100], + [212, 214, 105, 106, -52, -100], + [318, 214, 105, 106, -52, -100], + [0, 321, 105, 106, -52, -100] + ] + ], +} + +export const BONESPEAR_META: MissileMeta = { + name: "bonespear", + celFile: "BoneSpear", + width: 1024, + height: 347, + directions: 16, + framesPerDirection: 6, + animSpeed: 16, + groups: [ + [ + [0, 0, 57, 57, -28, -68], + [58, 0, 57, 57, -28, -68], + [116, 0, 57, 57, -28, -68], + [174, 0, 57, 57, -28, -68], + [232, 0, 57, 57, -28, -68], + [290, 0, 57, 57, -28, -68] + ], + [ + [348, 0, 58, 57, -27, -68], + [407, 0, 58, 57, -27, -68], + [466, 0, 58, 57, -27, -68], + [525, 0, 58, 57, -27, -68], + [584, 0, 58, 57, -27, -68], + [643, 0, 58, 57, -27, -68] + ], + [ + [702, 0, 60, 57, -31, -68], + [763, 0, 60, 57, -31, -68], + [824, 0, 60, 57, -31, -68], + [885, 0, 60, 57, -31, -68], + [946, 0, 60, 57, -31, -68], + [0, 58, 60, 57, -31, -68] + ], + [ + [61, 58, 58, 57, -29, -68], + [120, 58, 58, 57, -29, -68], + [179, 58, 58, 57, -29, -68], + [238, 58, 58, 57, -29, -68], + [297, 58, 58, 57, -29, -68], + [356, 58, 58, 57, -29, -68] + ], + [ + [415, 58, 57, 57, -28, -68], + [473, 58, 57, 57, -28, -68], + [531, 58, 57, 57, -28, -68], + [589, 58, 57, 57, -28, -68], + [647, 58, 57, 57, -28, -68], + [705, 58, 57, 57, -28, -68] + ], + [ + [763, 58, 68, 57, -28, -68], + [832, 58, 68, 57, -28, -68], + [901, 58, 68, 57, -28, -68], + [0, 116, 68, 57, -28, -68], + [69, 116, 68, 57, -28, -68], + [138, 116, 68, 57, -28, -68] + ], + [ + [207, 116, 56, 57, -27, -68], + [264, 116, 56, 57, -27, -68], + [321, 116, 56, 57, -27, -68], + [378, 116, 56, 57, -27, -68], + [435, 116, 56, 57, -27, -68], + [492, 116, 56, 57, -27, -68] + ], + [ + [549, 116, 69, 57, -40, -68], + [619, 116, 69, 57, -40, -68], + [689, 116, 69, 57, -40, -68], + [759, 116, 69, 57, -40, -68], + [829, 116, 69, 57, -40, -68], + [899, 116, 69, 57, -40, -68] + ], + [ + [0, 174, 57, 57, -28, -68], + [58, 174, 57, 57, -28, -68], + [116, 174, 57, 57, -28, -68], + [174, 174, 57, 57, -28, -68], + [232, 174, 57, 57, -28, -68], + [290, 174, 57, 57, -28, -68] + ], + [ + [348, 174, 65, 57, -28, -68], + [414, 174, 65, 57, -28, -68], + [480, 174, 65, 57, -28, -68], + [546, 174, 65, 57, -28, -68], + [612, 174, 65, 57, -28, -68], + [678, 174, 65, 57, -28, -68] + ], + [ + [744, 174, 66, 57, -28, -68], + [811, 174, 66, 57, -28, -68], + [878, 174, 66, 57, -28, -68], + [945, 174, 66, 57, -28, -68], + [0, 232, 66, 57, -28, -68], + [67, 232, 66, 57, -28, -68] + ], + [ + [134, 232, 56, 57, -27, -68], + [191, 232, 56, 57, -27, -68], + [248, 232, 56, 57, -27, -68], + [305, 232, 56, 57, -27, -68], + [362, 232, 56, 57, -27, -68], + [419, 232, 56, 57, -27, -68] + ], + [ + [476, 232, 56, 57, -27, -68], + [533, 232, 56, 57, -27, -68], + [590, 232, 56, 57, -27, -68], + [647, 232, 56, 57, -27, -68], + [704, 232, 56, 57, -27, -68], + [761, 232, 56, 57, -27, -68] + ], + [ + [818, 232, 67, 57, -38, -68], + [886, 232, 67, 57, -38, -68], + [954, 232, 67, 57, -38, -68], + [0, 290, 67, 57, -38, -68], + [68, 290, 67, 57, -38, -68], + [136, 290, 67, 57, -38, -68] + ], + [ + [204, 290, 66, 57, -37, -68], + [271, 290, 66, 57, -37, -68], + [338, 290, 66, 57, -37, -68], + [405, 290, 66, 57, -37, -68], + [472, 290, 66, 57, -37, -68], + [539, 290, 66, 57, -37, -68] + ], + [ + [606, 290, 57, 57, -28, -68], + [664, 290, 57, 57, -28, -68], + [722, 290, 57, 57, -28, -68], + [780, 290, 57, 57, -28, -68], + [838, 290, 57, 57, -28, -68], + [896, 290, 57, 57, -28, -68] + ] + ], +} + +export const BONESPIRIT_META: MissileMeta = { + name: "bonespirit", + celFile: "BoneSpirit", + width: 2048, + height: 499, + directions: 8, + framesPerDirection: 8, + animSpeed: 16, + groups: [ + [ + [0, 0, 123, 122, -56, -60], + [124, 0, 123, 122, -56, -60], + [248, 0, 123, 122, -56, -60], + [372, 0, 123, 122, -56, -60], + [496, 0, 123, 122, -56, -60], + [620, 0, 123, 122, -56, -60], + [744, 0, 123, 122, -56, -60], + [868, 0, 123, 122, -56, -60] + ], + [ + [992, 0, 125, 124, -57, -55], + [1118, 0, 125, 124, -57, -55], + [1244, 0, 125, 124, -57, -55], + [1370, 0, 125, 124, -57, -55], + [1496, 0, 125, 124, -57, -55], + [1622, 0, 125, 124, -57, -55], + [1748, 0, 125, 124, -57, -55], + [1874, 0, 125, 124, -57, -55] + ], + [ + [0, 125, 126, 124, -69, -55], + [127, 125, 126, 124, -69, -55], + [254, 125, 126, 124, -69, -55], + [381, 125, 126, 124, -69, -55], + [508, 125, 126, 124, -69, -55], + [635, 125, 126, 124, -69, -55], + [762, 125, 126, 124, -69, -55], + [889, 125, 126, 124, -69, -55] + ], + [ + [1016, 125, 124, 122, -68, -60], + [1141, 125, 124, 122, -68, -60], + [1266, 125, 124, 122, -68, -60], + [1391, 125, 124, 122, -68, -60], + [1516, 125, 124, 122, -68, -60], + [1641, 125, 124, 122, -68, -60], + [1766, 125, 124, 122, -68, -60], + [1891, 125, 124, 122, -68, -60] + ], + [ + [0, 250, 123, 121, -62, -61], + [124, 250, 123, 121, -62, -61], + [248, 250, 123, 121, -62, -61], + [372, 250, 123, 121, -62, -61], + [496, 250, 123, 121, -62, -61], + [620, 250, 123, 121, -62, -61], + [744, 250, 123, 121, -62, -61], + [868, 250, 123, 121, -62, -61] + ], + [ + [992, 250, 124, 123, -54, -58], + [1117, 250, 124, 123, -54, -58], + [1242, 250, 124, 123, -54, -58], + [1367, 250, 124, 123, -54, -58], + [1492, 250, 124, 123, -54, -58], + [1617, 250, 124, 123, -54, -58], + [1742, 250, 124, 123, -54, -58], + [1867, 250, 124, 123, -54, -58] + ], + [ + [0, 374, 127, 125, -64, -54], + [128, 374, 127, 125, -64, -54], + [256, 374, 127, 125, -64, -54], + [384, 374, 127, 125, -64, -54], + [512, 374, 127, 125, -64, -54], + [640, 374, 127, 125, -64, -54], + [768, 374, 127, 125, -64, -54], + [896, 374, 127, 125, -64, -54] + ], + [ + [1024, 374, 125, 123, -71, -58], + [1150, 374, 125, 123, -71, -58], + [1276, 374, 125, 123, -71, -58], + [1402, 374, 125, 123, -71, -58], + [1528, 374, 125, 123, -71, -58], + [1654, 374, 125, 123, -71, -58], + [1780, 374, 125, 123, -71, -58], + [1906, 374, 125, 123, -71, -58] + ] + ], +} + +export const BONESPIRITEXPLODE_META: MissileMeta = { + name: "bonespiritexplode", + celFile: "BoneSpiritExplode", + width: 512, + height: 569, + directions: 1, + framesPerDirection: 13, + animSpeed: 16, + groups: [ + [ + [0, 0, 128, 113, -62, -100], + [129, 0, 128, 113, -62, -100], + [258, 0, 128, 113, -62, -100], + [0, 114, 128, 113, -62, -100], + [129, 114, 128, 113, -62, -100], + [258, 114, 128, 113, -62, -100], + [0, 228, 128, 113, -62, -100], + [129, 228, 128, 113, -62, -100], + [258, 228, 128, 113, -62, -100], + [0, 342, 128, 113, -62, -100], + [129, 342, 128, 113, -62, -100], + [258, 342, 128, 113, -62, -100], + [0, 456, 128, 113, -62, -100] + ] + ], +} + +export const POISONNOVA_META: MissileMeta = { + name: "poisonnova", + celFile: "poisonNova", + width: 4096, + height: 1369, + directions: 32, + framesPerDirection: 30, + animSpeed: 16, + groups: [ + [ + [0, 0, 104, 55, -19, -95], + [105, 0, 104, 55, -19, -95], + [210, 0, 104, 55, -19, -95], + [315, 0, 104, 55, -19, -95], + [420, 0, 104, 55, -19, -95], + [525, 0, 104, 55, -19, -95], + [630, 0, 104, 55, -19, -95], + [735, 0, 104, 55, -19, -95], + [840, 0, 104, 55, -19, -95], + [945, 0, 104, 55, -19, -95], + [1050, 0, 104, 55, -19, -95], + [1155, 0, 104, 55, -19, -95], + [1260, 0, 104, 55, -19, -95], + [1365, 0, 104, 55, -19, -95], + [1470, 0, 104, 55, -19, -95], + [1575, 0, 104, 55, -19, -95], + [1680, 0, 104, 55, -19, -95], + [1785, 0, 104, 55, -19, -95], + [1890, 0, 104, 55, -19, -95], + [1995, 0, 104, 55, -19, -95], + [2100, 0, 104, 55, -19, -95], + [2205, 0, 104, 55, -19, -95], + [2310, 0, 104, 55, -19, -95], + [2415, 0, 104, 55, -19, -95], + [2520, 0, 104, 55, -19, -95], + [2625, 0, 104, 55, -19, -95], + [2730, 0, 104, 55, -19, -95], + [2835, 0, 104, 55, -19, -95], + [2940, 0, 104, 55, -19, -95], + [3045, 0, 104, 55, -19, -95] + ], + [ + [3150, 0, 99, 57, -13, -66], + [3250, 0, 99, 57, -13, -66], + [3350, 0, 99, 57, -13, -66], + [3450, 0, 99, 57, -13, -66], + [3550, 0, 99, 57, -13, -66], + [3650, 0, 99, 57, -13, -66], + [3750, 0, 99, 57, -13, -66], + [3850, 0, 99, 57, -13, -66], + [3950, 0, 99, 57, -13, -66], + [0, 58, 99, 57, -13, -66], + [100, 58, 99, 57, -13, -66], + [200, 58, 99, 57, -13, -66], + [300, 58, 99, 57, -13, -66], + [400, 58, 99, 57, -13, -66], + [500, 58, 99, 57, -13, -66], + [600, 58, 99, 57, -13, -66], + [700, 58, 99, 57, -13, -66], + [800, 58, 99, 57, -13, -66], + [900, 58, 99, 57, -13, -66], + [1000, 58, 99, 57, -13, -66], + [1100, 58, 99, 57, -13, -66], + [1200, 58, 99, 57, -13, -66], + [1300, 58, 99, 57, -13, -66], + [1400, 58, 99, 57, -13, -66], + [1500, 58, 99, 57, -13, -66], + [1600, 58, 99, 57, -13, -66], + [1700, 58, 99, 57, -13, -66], + [1800, 58, 99, 57, -13, -66], + [1900, 58, 99, 57, -13, -66], + [2000, 58, 99, 57, -13, -66] + ], + [ + [2100, 58, 99, 56, -86, -64], + [2200, 58, 99, 56, -86, -64], + [2300, 58, 99, 56, -86, -64], + [2400, 58, 99, 56, -86, -64], + [2500, 58, 99, 56, -86, -64], + [2600, 58, 99, 56, -86, -64], + [2700, 58, 99, 56, -86, -64], + [2800, 58, 99, 56, -86, -64], + [2900, 58, 99, 56, -86, -64], + [3000, 58, 99, 56, -86, -64], + [3100, 58, 99, 56, -86, -64], + [3200, 58, 99, 56, -86, -64], + [3300, 58, 99, 56, -86, -64], + [3400, 58, 99, 56, -86, -64], + [3500, 58, 99, 56, -86, -64], + [3600, 58, 99, 56, -86, -64], + [3700, 58, 99, 56, -86, -64], + [3800, 58, 99, 56, -86, -64], + [3900, 58, 99, 56, -86, -64], + [0, 116, 99, 56, -86, -64], + [100, 116, 99, 56, -86, -64], + [200, 116, 99, 56, -86, -64], + [300, 116, 99, 56, -86, -64], + [400, 116, 99, 56, -86, -64], + [500, 116, 99, 56, -86, -64], + [600, 116, 99, 56, -86, -64], + [700, 116, 99, 56, -86, -64], + [800, 116, 99, 56, -86, -64], + [900, 116, 99, 56, -86, -64], + [1000, 116, 99, 56, -86, -64] + ], + [ + [1100, 116, 101, 56, -86, -96], + [1202, 116, 101, 56, -86, -96], + [1304, 116, 101, 56, -86, -96], + [1406, 116, 101, 56, -86, -96], + [1508, 116, 101, 56, -86, -96], + [1610, 116, 101, 56, -86, -96], + [1712, 116, 101, 56, -86, -96], + [1814, 116, 101, 56, -86, -96], + [1916, 116, 101, 56, -86, -96], + [2018, 116, 101, 56, -86, -96], + [2120, 116, 101, 56, -86, -96], + [2222, 116, 101, 56, -86, -96], + [2324, 116, 101, 56, -86, -96], + [2426, 116, 101, 56, -86, -96], + [2528, 116, 101, 56, -86, -96], + [2630, 116, 101, 56, -86, -96], + [2732, 116, 101, 56, -86, -96], + [2834, 116, 101, 56, -86, -96], + [2936, 116, 101, 56, -86, -96], + [3038, 116, 101, 56, -86, -96], + [3140, 116, 101, 56, -86, -96], + [3242, 116, 101, 56, -86, -96], + [3344, 116, 101, 56, -86, -96], + [3446, 116, 101, 56, -86, -96], + [3548, 116, 101, 56, -86, -96], + [3650, 116, 101, 56, -86, -96], + [3752, 116, 101, 56, -86, -96], + [3854, 116, 101, 56, -86, -96], + [3956, 116, 101, 56, -86, -96], + [0, 173, 101, 56, -86, -96] + ], + [ + [102, 173, 28, 77, -12, -110], + [131, 173, 28, 77, -12, -110], + [160, 173, 28, 77, -12, -110], + [189, 173, 28, 77, -12, -110], + [218, 173, 28, 77, -12, -110], + [247, 173, 28, 77, -12, -110], + [276, 173, 28, 77, -12, -110], + [305, 173, 28, 77, -12, -110], + [334, 173, 28, 77, -12, -110], + [363, 173, 28, 77, -12, -110], + [392, 173, 28, 77, -12, -110], + [421, 173, 28, 77, -12, -110], + [450, 173, 28, 77, -12, -110], + [479, 173, 28, 77, -12, -110], + [508, 173, 28, 77, -12, -110], + [537, 173, 28, 77, -12, -110], + [566, 173, 28, 77, -12, -110], + [595, 173, 28, 77, -12, -110], + [624, 173, 28, 77, -12, -110], + [653, 173, 28, 77, -12, -110], + [682, 173, 28, 77, -12, -110], + [711, 173, 28, 77, -12, -110], + [740, 173, 28, 77, -12, -110], + [769, 173, 28, 77, -12, -110], + [798, 173, 28, 77, -12, -110], + [827, 173, 28, 77, -12, -110], + [856, 173, 28, 77, -12, -110], + [885, 173, 28, 77, -12, -110], + [914, 173, 28, 77, -12, -110], + [943, 173, 28, 77, -12, -110] + ], + [ + [972, 173, 138, 29, -20, -66], + [1111, 173, 138, 29, -20, -66], + [1250, 173, 138, 29, -20, -66], + [1389, 173, 138, 29, -20, -66], + [1528, 173, 138, 29, -20, -66], + [1667, 173, 138, 29, -20, -66], + [1806, 173, 138, 29, -20, -66], + [1945, 173, 138, 29, -20, -66], + [2084, 173, 138, 29, -20, -66], + [2223, 173, 138, 29, -20, -66], + [2362, 173, 138, 29, -20, -66], + [2501, 173, 138, 29, -20, -66], + [2640, 173, 138, 29, -20, -66], + [2779, 173, 138, 29, -20, -66], + [2918, 173, 138, 29, -20, -66], + [3057, 173, 138, 29, -20, -66], + [3196, 173, 138, 29, -20, -66], + [3335, 173, 138, 29, -20, -66], + [3474, 173, 138, 29, -20, -66], + [3613, 173, 138, 29, -20, -66], + [3752, 173, 138, 29, -20, -66], + [3891, 173, 138, 29, -20, -66], + [0, 251, 138, 29, -20, -66], + [139, 251, 138, 29, -20, -66], + [278, 251, 138, 29, -20, -66], + [417, 251, 138, 29, -20, -66], + [556, 251, 138, 29, -20, -66], + [695, 251, 138, 29, -20, -66], + [834, 251, 138, 29, -20, -66], + [973, 251, 138, 29, -20, -66] + ], + [ + [1112, 251, 28, 72, -16, -64], + [1141, 251, 28, 72, -16, -64], + [1170, 251, 28, 72, -16, -64], + [1199, 251, 28, 72, -16, -64], + [1228, 251, 28, 72, -16, -64], + [1257, 251, 28, 72, -16, -64], + [1286, 251, 28, 72, -16, -64], + [1315, 251, 28, 72, -16, -64], + [1344, 251, 28, 72, -16, -64], + [1373, 251, 28, 72, -16, -64], + [1402, 251, 28, 72, -16, -64], + [1431, 251, 28, 72, -16, -64], + [1460, 251, 28, 72, -16, -64], + [1489, 251, 28, 72, -16, -64], + [1518, 251, 28, 72, -16, -64], + [1547, 251, 28, 72, -16, -64], + [1576, 251, 28, 72, -16, -64], + [1605, 251, 28, 72, -16, -64], + [1634, 251, 28, 72, -16, -64], + [1663, 251, 28, 72, -16, -64], + [1692, 251, 28, 72, -16, -64], + [1721, 251, 28, 72, -16, -64], + [1750, 251, 28, 72, -16, -64], + [1779, 251, 28, 72, -16, -64], + [1808, 251, 28, 72, -16, -64], + [1837, 251, 28, 72, -16, -64], + [1866, 251, 28, 72, -16, -64], + [1895, 251, 28, 72, -16, -64], + [1924, 251, 28, 72, -16, -64], + [1953, 251, 28, 72, -16, -64] + ], + [ + [1982, 251, 138, 28, -118, -66], + [2121, 251, 138, 28, -118, -66], + [2260, 251, 138, 28, -118, -66], + [2399, 251, 138, 28, -118, -66], + [2538, 251, 138, 28, -118, -66], + [2677, 251, 138, 28, -118, -66], + [2816, 251, 138, 28, -118, -66], + [2955, 251, 138, 28, -118, -66], + [3094, 251, 138, 28, -118, -66], + [3233, 251, 138, 28, -118, -66], + [3372, 251, 138, 28, -118, -66], + [3511, 251, 138, 28, -118, -66], + [3650, 251, 138, 28, -118, -66], + [3789, 251, 138, 28, -118, -66], + [3928, 251, 138, 28, -118, -66], + [0, 324, 138, 28, -118, -66], + [139, 324, 138, 28, -118, -66], + [278, 324, 138, 28, -118, -66], + [417, 324, 138, 28, -118, -66], + [556, 324, 138, 28, -118, -66], + [695, 324, 138, 28, -118, -66], + [834, 324, 138, 28, -118, -66], + [973, 324, 138, 28, -118, -66], + [1112, 324, 138, 28, -118, -66], + [1251, 324, 138, 28, -118, -66], + [1390, 324, 138, 28, -118, -66], + [1529, 324, 138, 28, -118, -66], + [1668, 324, 138, 28, -118, -66], + [1807, 324, 138, 28, -118, -66], + [1946, 324, 138, 28, -118, -66] + ], + [ + [2085, 324, 66, 67, -15, -106], + [2152, 324, 66, 67, -15, -106], + [2219, 324, 66, 67, -15, -106], + [2286, 324, 66, 67, -15, -106], + [2353, 324, 66, 67, -15, -106], + [2420, 324, 66, 67, -15, -106], + [2487, 324, 66, 67, -15, -106], + [2554, 324, 66, 67, -15, -106], + [2621, 324, 66, 67, -15, -106], + [2688, 324, 66, 67, -15, -106], + [2755, 324, 66, 67, -15, -106], + [2822, 324, 66, 67, -15, -106], + [2889, 324, 66, 67, -15, -106], + [2956, 324, 66, 67, -15, -106], + [3023, 324, 66, 67, -15, -106], + [3090, 324, 66, 67, -15, -106], + [3157, 324, 66, 67, -15, -106], + [3224, 324, 66, 67, -15, -106], + [3291, 324, 66, 67, -15, -106], + [3358, 324, 66, 67, -15, -106], + [3425, 324, 66, 67, -15, -106], + [3492, 324, 66, 67, -15, -106], + [3559, 324, 66, 67, -15, -106], + [3626, 324, 66, 67, -15, -106], + [3693, 324, 66, 67, -15, -106], + [3760, 324, 66, 67, -15, -106], + [3827, 324, 66, 67, -15, -106], + [3894, 324, 66, 67, -15, -106], + [3961, 324, 66, 67, -15, -106], + [4028, 324, 66, 67, -15, -106] + ], + [ + [0, 392, 131, 36, -20, -76], + [132, 392, 131, 36, -20, -76], + [264, 392, 131, 36, -20, -76], + [396, 392, 131, 36, -20, -76], + [528, 392, 131, 36, -20, -76], + [660, 392, 131, 36, -20, -76], + [792, 392, 131, 36, -20, -76], + [924, 392, 131, 36, -20, -76], + [1056, 392, 131, 36, -20, -76], + [1188, 392, 131, 36, -20, -76], + [1320, 392, 131, 36, -20, -76], + [1452, 392, 131, 36, -20, -76], + [1584, 392, 131, 36, -20, -76], + [1716, 392, 131, 36, -20, -76], + [1848, 392, 131, 36, -20, -76], + [1980, 392, 131, 36, -20, -76], + [2112, 392, 131, 36, -20, -76], + [2244, 392, 131, 36, -20, -76], + [2376, 392, 131, 36, -20, -76], + [2508, 392, 131, 36, -20, -76], + [2640, 392, 131, 36, -20, -76], + [2772, 392, 131, 36, -20, -76], + [2904, 392, 131, 36, -20, -76], + [3036, 392, 131, 36, -20, -76], + [3168, 392, 131, 36, -20, -76], + [3300, 392, 131, 36, -20, -76], + [3432, 392, 131, 36, -20, -76], + [3564, 392, 131, 36, -20, -76], + [3696, 392, 131, 36, -20, -76], + [3828, 392, 131, 36, -20, -76] + ], + [ + [3960, 392, 130, 38, -22, -63], + [0, 431, 130, 38, -22, -63], + [131, 431, 130, 38, -22, -63], + [262, 431, 130, 38, -22, -63], + [393, 431, 130, 38, -22, -63], + [524, 431, 130, 38, -22, -63], + [655, 431, 130, 38, -22, -63], + [786, 431, 130, 38, -22, -63], + [917, 431, 130, 38, -22, -63], + [1048, 431, 130, 38, -22, -63], + [1179, 431, 130, 38, -22, -63], + [1310, 431, 130, 38, -22, -63], + [1441, 431, 130, 38, -22, -63], + [1572, 431, 130, 38, -22, -63], + [1703, 431, 130, 38, -22, -63], + [1834, 431, 130, 38, -22, -63], + [1965, 431, 130, 38, -22, -63], + [2096, 431, 130, 38, -22, -63], + [2227, 431, 130, 38, -22, -63], + [2358, 431, 130, 38, -22, -63], + [2489, 431, 130, 38, -22, -63], + [2620, 431, 130, 38, -22, -63], + [2751, 431, 130, 38, -22, -63], + [2882, 431, 130, 38, -22, -63], + [3013, 431, 130, 38, -22, -63], + [3144, 431, 130, 38, -22, -63], + [3275, 431, 130, 38, -22, -63], + [3406, 431, 130, 38, -22, -63], + [3537, 431, 130, 38, -22, -63], + [3668, 431, 130, 38, -22, -63] + ], + [ + [3799, 431, 67, 67, -19, -63], + [3867, 431, 67, 67, -19, -63], + [3935, 431, 67, 67, -19, -63], + [4003, 431, 67, 67, -19, -63], + [0, 499, 67, 67, -19, -63], + [68, 499, 67, 67, -19, -63], + [136, 499, 67, 67, -19, -63], + [204, 499, 67, 67, -19, -63], + [272, 499, 67, 67, -19, -63], + [340, 499, 67, 67, -19, -63], + [408, 499, 67, 67, -19, -63], + [476, 499, 67, 67, -19, -63], + [544, 499, 67, 67, -19, -63], + [612, 499, 67, 67, -19, -63], + [680, 499, 67, 67, -19, -63], + [748, 499, 67, 67, -19, -63], + [816, 499, 67, 67, -19, -63], + [884, 499, 67, 67, -19, -63], + [952, 499, 67, 67, -19, -63], + [1020, 499, 67, 67, -19, -63], + [1088, 499, 67, 67, -19, -63], + [1156, 499, 67, 67, -19, -63], + [1224, 499, 67, 67, -19, -63], + [1292, 499, 67, 67, -19, -63], + [1360, 499, 67, 67, -19, -63], + [1428, 499, 67, 67, -19, -63], + [1496, 499, 67, 67, -19, -63], + [1564, 499, 67, 67, -19, -63], + [1632, 499, 67, 67, -19, -63], + [1700, 499, 67, 67, -19, -63] + ], + [ + [1768, 499, 62, 73, -51, -70], + [1831, 499, 62, 73, -51, -70], + [1894, 499, 62, 73, -51, -70], + [1957, 499, 62, 73, -51, -70], + [2020, 499, 62, 73, -51, -70], + [2083, 499, 62, 73, -51, -70], + [2146, 499, 62, 73, -51, -70], + [2209, 499, 62, 73, -51, -70], + [2272, 499, 62, 73, -51, -70], + [2335, 499, 62, 73, -51, -70], + [2398, 499, 62, 73, -51, -70], + [2461, 499, 62, 73, -51, -70], + [2524, 499, 62, 73, -51, -70], + [2587, 499, 62, 73, -51, -70], + [2650, 499, 62, 73, -51, -70], + [2713, 499, 62, 73, -51, -70], + [2776, 499, 62, 73, -51, -70], + [2839, 499, 62, 73, -51, -70], + [2902, 499, 62, 73, -51, -70], + [2965, 499, 62, 73, -51, -70], + [3028, 499, 62, 73, -51, -70], + [3091, 499, 62, 73, -51, -70], + [3154, 499, 62, 73, -51, -70], + [3217, 499, 62, 73, -51, -70], + [3280, 499, 62, 73, -51, -70], + [3343, 499, 62, 73, -51, -70], + [3406, 499, 62, 73, -51, -70], + [3469, 499, 62, 73, -51, -70], + [3532, 499, 62, 73, -51, -70], + [3595, 499, 62, 73, -51, -70] + ], + [ + [3658, 499, 127, 39, -110, -65], + [3786, 499, 127, 39, -110, -65], + [3914, 499, 127, 39, -110, -65], + [0, 573, 127, 39, -110, -65], + [128, 573, 127, 39, -110, -65], + [256, 573, 127, 39, -110, -65], + [384, 573, 127, 39, -110, -65], + [512, 573, 127, 39, -110, -65], + [640, 573, 127, 39, -110, -65], + [768, 573, 127, 39, -110, -65], + [896, 573, 127, 39, -110, -65], + [1024, 573, 127, 39, -110, -65], + [1152, 573, 127, 39, -110, -65], + [1280, 573, 127, 39, -110, -65], + [1408, 573, 127, 39, -110, -65], + [1536, 573, 127, 39, -110, -65], + [1664, 573, 127, 39, -110, -65], + [1792, 573, 127, 39, -110, -65], + [1920, 573, 127, 39, -110, -65], + [2048, 573, 127, 39, -110, -65], + [2176, 573, 127, 39, -110, -65], + [2304, 573, 127, 39, -110, -65], + [2432, 573, 127, 39, -110, -65], + [2560, 573, 127, 39, -110, -65], + [2688, 573, 127, 39, -110, -65], + [2816, 573, 127, 39, -110, -65], + [2944, 573, 127, 39, -110, -65], + [3072, 573, 127, 39, -110, -65], + [3200, 573, 127, 39, -110, -65], + [3328, 573, 127, 39, -110, -65] + ], + [ + [3456, 573, 129, 39, -110, -79], + [3586, 573, 129, 39, -110, -79], + [3716, 573, 129, 39, -110, -79], + [3846, 573, 129, 39, -110, -79], + [0, 613, 129, 39, -110, -79], + [130, 613, 129, 39, -110, -79], + [260, 613, 129, 39, -110, -79], + [390, 613, 129, 39, -110, -79], + [520, 613, 129, 39, -110, -79], + [650, 613, 129, 39, -110, -79], + [780, 613, 129, 39, -110, -79], + [910, 613, 129, 39, -110, -79], + [1040, 613, 129, 39, -110, -79], + [1170, 613, 129, 39, -110, -79], + [1300, 613, 129, 39, -110, -79], + [1430, 613, 129, 39, -110, -79], + [1560, 613, 129, 39, -110, -79], + [1690, 613, 129, 39, -110, -79], + [1820, 613, 129, 39, -110, -79], + [1950, 613, 129, 39, -110, -79], + [2080, 613, 129, 39, -110, -79], + [2210, 613, 129, 39, -110, -79], + [2340, 613, 129, 39, -110, -79], + [2470, 613, 129, 39, -110, -79], + [2600, 613, 129, 39, -110, -79], + [2730, 613, 129, 39, -110, -79], + [2860, 613, 129, 39, -110, -79], + [2990, 613, 129, 39, -110, -79], + [3120, 613, 129, 39, -110, -79], + [3250, 613, 129, 39, -110, -79] + ], + [ + [3380, 613, 62, 69, -49, -107], + [3443, 613, 62, 69, -49, -107], + [3506, 613, 62, 69, -49, -107], + [3569, 613, 62, 69, -49, -107], + [3632, 613, 62, 69, -49, -107], + [3695, 613, 62, 69, -49, -107], + [3758, 613, 62, 69, -49, -107], + [3821, 613, 62, 69, -49, -107], + [3884, 613, 62, 69, -49, -107], + [3947, 613, 62, 69, -49, -107], + [4010, 613, 62, 69, -49, -107], + [0, 683, 62, 69, -49, -107], + [63, 683, 62, 69, -49, -107], + [126, 683, 62, 69, -49, -107], + [189, 683, 62, 69, -49, -107], + [252, 683, 62, 69, -49, -107], + [315, 683, 62, 69, -49, -107], + [378, 683, 62, 69, -49, -107], + [441, 683, 62, 69, -49, -107], + [504, 683, 62, 69, -49, -107], + [567, 683, 62, 69, -49, -107], + [630, 683, 62, 69, -49, -107], + [693, 683, 62, 69, -49, -107], + [756, 683, 62, 69, -49, -107], + [819, 683, 62, 69, -49, -107], + [882, 683, 62, 69, -49, -107], + [945, 683, 62, 69, -49, -107], + [1008, 683, 62, 69, -49, -107], + [1071, 683, 62, 69, -49, -107], + [1134, 683, 62, 69, -49, -107] + ], + [ + [1197, 683, 39, 76, -11, -109], + [1237, 683, 39, 76, -11, -109], + [1277, 683, 39, 76, -11, -109], + [1317, 683, 39, 76, -11, -109], + [1357, 683, 39, 76, -11, -109], + [1397, 683, 39, 76, -11, -109], + [1437, 683, 39, 76, -11, -109], + [1477, 683, 39, 76, -11, -109], + [1517, 683, 39, 76, -11, -109], + [1557, 683, 39, 76, -11, -109], + [1597, 683, 39, 76, -11, -109], + [1637, 683, 39, 76, -11, -109], + [1677, 683, 39, 76, -11, -109], + [1717, 683, 39, 76, -11, -109], + [1757, 683, 39, 76, -11, -109], + [1797, 683, 39, 76, -11, -109], + [1837, 683, 39, 76, -11, -109], + [1877, 683, 39, 76, -11, -109], + [1917, 683, 39, 76, -11, -109], + [1957, 683, 39, 76, -11, -109], + [1997, 683, 39, 76, -11, -109], + [2037, 683, 39, 76, -11, -109], + [2077, 683, 39, 76, -11, -109], + [2117, 683, 39, 76, -11, -109], + [2157, 683, 39, 76, -11, -109], + [2197, 683, 39, 76, -11, -109], + [2237, 683, 39, 76, -11, -109], + [2277, 683, 39, 76, -11, -109], + [2317, 683, 39, 76, -11, -109], + [2357, 683, 39, 76, -11, -109] + ], + [ + [2397, 683, 82, 63, -12, -98], + [2480, 683, 82, 63, -12, -98], + [2563, 683, 82, 63, -12, -98], + [2646, 683, 82, 63, -12, -98], + [2729, 683, 82, 63, -12, -98], + [2812, 683, 82, 63, -12, -98], + [2895, 683, 82, 63, -12, -98], + [2978, 683, 82, 63, -12, -98], + [3061, 683, 82, 63, -12, -98], + [3144, 683, 82, 63, -12, -98], + [3227, 683, 82, 63, -12, -98], + [3310, 683, 82, 63, -12, -98], + [3393, 683, 82, 63, -12, -98], + [3476, 683, 82, 63, -12, -98], + [3559, 683, 82, 63, -12, -98], + [3642, 683, 82, 63, -12, -98], + [3725, 683, 82, 63, -12, -98], + [3808, 683, 82, 63, -12, -98], + [3891, 683, 82, 63, -12, -98], + [3974, 683, 82, 63, -12, -98], + [0, 760, 82, 63, -12, -98], + [83, 760, 82, 63, -12, -98], + [166, 760, 82, 63, -12, -98], + [249, 760, 82, 63, -12, -98], + [332, 760, 82, 63, -12, -98], + [415, 760, 82, 63, -12, -98], + [498, 760, 82, 63, -12, -98], + [581, 760, 82, 63, -12, -98], + [664, 760, 82, 63, -12, -98], + [747, 760, 82, 63, -12, -98] + ], + [ + [830, 760, 122, 47, -21, -86], + [953, 760, 122, 47, -21, -86], + [1076, 760, 122, 47, -21, -86], + [1199, 760, 122, 47, -21, -86], + [1322, 760, 122, 47, -21, -86], + [1445, 760, 122, 47, -21, -86], + [1568, 760, 122, 47, -21, -86], + [1691, 760, 122, 47, -21, -86], + [1814, 760, 122, 47, -21, -86], + [1937, 760, 122, 47, -21, -86], + [2060, 760, 122, 47, -21, -86], + [2183, 760, 122, 47, -21, -86], + [2306, 760, 122, 47, -21, -86], + [2429, 760, 122, 47, -21, -86], + [2552, 760, 122, 47, -21, -86], + [2675, 760, 122, 47, -21, -86], + [2798, 760, 122, 47, -21, -86], + [2921, 760, 122, 47, -21, -86], + [3044, 760, 122, 47, -21, -86], + [3167, 760, 122, 47, -21, -86], + [3290, 760, 122, 47, -21, -86], + [3413, 760, 122, 47, -21, -86], + [3536, 760, 122, 47, -21, -86], + [3659, 760, 122, 47, -21, -86], + [3782, 760, 122, 47, -21, -86], + [3905, 760, 122, 47, -21, -86], + [0, 824, 122, 47, -21, -86], + [123, 824, 122, 47, -21, -86], + [246, 824, 122, 47, -21, -86], + [369, 824, 122, 47, -21, -86] + ], + [ + [492, 824, 138, 30, -21, -69], + [631, 824, 138, 30, -21, -69], + [770, 824, 138, 30, -21, -69], + [909, 824, 138, 30, -21, -69], + [1048, 824, 138, 30, -21, -69], + [1187, 824, 138, 30, -21, -69], + [1326, 824, 138, 30, -21, -69], + [1465, 824, 138, 30, -21, -69], + [1604, 824, 138, 30, -21, -69], + [1743, 824, 138, 30, -21, -69], + [1882, 824, 138, 30, -21, -69], + [2021, 824, 138, 30, -21, -69], + [2160, 824, 138, 30, -21, -69], + [2299, 824, 138, 30, -21, -69], + [2438, 824, 138, 30, -21, -69], + [2577, 824, 138, 30, -21, -69], + [2716, 824, 138, 30, -21, -69], + [2855, 824, 138, 30, -21, -69], + [2994, 824, 138, 30, -21, -69], + [3133, 824, 138, 30, -21, -69], + [3272, 824, 138, 30, -21, -69], + [3411, 824, 138, 30, -21, -69], + [3550, 824, 138, 30, -21, -69], + [3689, 824, 138, 30, -21, -69], + [3828, 824, 138, 30, -21, -69], + [0, 872, 138, 30, -21, -69], + [139, 872, 138, 30, -21, -69], + [278, 872, 138, 30, -21, -69], + [417, 872, 138, 30, -21, -69], + [556, 872, 138, 30, -21, -69] + ], + [ + [695, 872, 135, 34, -20, -67], + [831, 872, 135, 34, -20, -67], + [967, 872, 135, 34, -20, -67], + [1103, 872, 135, 34, -20, -67], + [1239, 872, 135, 34, -20, -67], + [1375, 872, 135, 34, -20, -67], + [1511, 872, 135, 34, -20, -67], + [1647, 872, 135, 34, -20, -67], + [1783, 872, 135, 34, -20, -67], + [1919, 872, 135, 34, -20, -67], + [2055, 872, 135, 34, -20, -67], + [2191, 872, 135, 34, -20, -67], + [2327, 872, 135, 34, -20, -67], + [2463, 872, 135, 34, -20, -67], + [2599, 872, 135, 34, -20, -67], + [2735, 872, 135, 34, -20, -67], + [2871, 872, 135, 34, -20, -67], + [3007, 872, 135, 34, -20, -67], + [3143, 872, 135, 34, -20, -67], + [3279, 872, 135, 34, -20, -67], + [3415, 872, 135, 34, -20, -67], + [3551, 872, 135, 34, -20, -67], + [3687, 872, 135, 34, -20, -67], + [3823, 872, 135, 34, -20, -67], + [3959, 872, 135, 34, -20, -67], + [0, 907, 135, 34, -20, -67], + [136, 907, 135, 34, -20, -67], + [272, 907, 135, 34, -20, -67], + [408, 907, 135, 34, -20, -67], + [544, 907, 135, 34, -20, -67] + ], + [ + [680, 907, 116, 47, -16, -64], + [797, 907, 116, 47, -16, -64], + [914, 907, 116, 47, -16, -64], + [1031, 907, 116, 47, -16, -64], + [1148, 907, 116, 47, -16, -64], + [1265, 907, 116, 47, -16, -64], + [1382, 907, 116, 47, -16, -64], + [1499, 907, 116, 47, -16, -64], + [1616, 907, 116, 47, -16, -64], + [1733, 907, 116, 47, -16, -64], + [1850, 907, 116, 47, -16, -64], + [1967, 907, 116, 47, -16, -64], + [2084, 907, 116, 47, -16, -64], + [2201, 907, 116, 47, -16, -64], + [2318, 907, 116, 47, -16, -64], + [2435, 907, 116, 47, -16, -64], + [2552, 907, 116, 47, -16, -64], + [2669, 907, 116, 47, -16, -64], + [2786, 907, 116, 47, -16, -64], + [2903, 907, 116, 47, -16, -64], + [3020, 907, 116, 47, -16, -64], + [3137, 907, 116, 47, -16, -64], + [3254, 907, 116, 47, -16, -64], + [3371, 907, 116, 47, -16, -64], + [3488, 907, 116, 47, -16, -64], + [3605, 907, 116, 47, -16, -64], + [3722, 907, 116, 47, -16, -64], + [3839, 907, 116, 47, -16, -64], + [3956, 907, 116, 47, -16, -64], + [0, 955, 116, 47, -16, -64] + ], + [ + [117, 955, 85, 63, -17, -64], + [203, 955, 85, 63, -17, -64], + [289, 955, 85, 63, -17, -64], + [375, 955, 85, 63, -17, -64], + [461, 955, 85, 63, -17, -64], + [547, 955, 85, 63, -17, -64], + [633, 955, 85, 63, -17, -64], + [719, 955, 85, 63, -17, -64], + [805, 955, 85, 63, -17, -64], + [891, 955, 85, 63, -17, -64], + [977, 955, 85, 63, -17, -64], + [1063, 955, 85, 63, -17, -64], + [1149, 955, 85, 63, -17, -64], + [1235, 955, 85, 63, -17, -64], + [1321, 955, 85, 63, -17, -64], + [1407, 955, 85, 63, -17, -64], + [1493, 955, 85, 63, -17, -64], + [1579, 955, 85, 63, -17, -64], + [1665, 955, 85, 63, -17, -64], + [1751, 955, 85, 63, -17, -64], + [1837, 955, 85, 63, -17, -64], + [1923, 955, 85, 63, -17, -64], + [2009, 955, 85, 63, -17, -64], + [2095, 955, 85, 63, -17, -64], + [2181, 955, 85, 63, -17, -64], + [2267, 955, 85, 63, -17, -64], + [2353, 955, 85, 63, -17, -64], + [2439, 955, 85, 63, -17, -64], + [2525, 955, 85, 63, -17, -64], + [2611, 955, 85, 63, -17, -64] + ], + [ + [2697, 955, 39, 74, -13, -70], + [2737, 955, 39, 74, -13, -70], + [2777, 955, 39, 74, -13, -70], + [2817, 955, 39, 74, -13, -70], + [2857, 955, 39, 74, -13, -70], + [2897, 955, 39, 74, -13, -70], + [2937, 955, 39, 74, -13, -70], + [2977, 955, 39, 74, -13, -70], + [3017, 955, 39, 74, -13, -70], + [3057, 955, 39, 74, -13, -70], + [3097, 955, 39, 74, -13, -70], + [3137, 955, 39, 74, -13, -70], + [3177, 955, 39, 74, -13, -70], + [3217, 955, 39, 74, -13, -70], + [3257, 955, 39, 74, -13, -70], + [3297, 955, 39, 74, -13, -70], + [3337, 955, 39, 74, -13, -70], + [3377, 955, 39, 74, -13, -70], + [3417, 955, 39, 74, -13, -70], + [3457, 955, 39, 74, -13, -70], + [3497, 955, 39, 74, -13, -70], + [3537, 955, 39, 74, -13, -70], + [3577, 955, 39, 74, -13, -70], + [3617, 955, 39, 74, -13, -70], + [3657, 955, 39, 74, -13, -70], + [3697, 955, 39, 74, -13, -70], + [3737, 955, 39, 74, -13, -70], + [3777, 955, 39, 74, -13, -70], + [3817, 955, 39, 74, -13, -70], + [3857, 955, 39, 74, -13, -70] + ], + [ + [3897, 955, 44, 69, -29, -66], + [3942, 955, 44, 69, -29, -66], + [3987, 955, 44, 69, -29, -66], + [4032, 955, 44, 69, -29, -66], + [0, 1030, 44, 69, -29, -66], + [45, 1030, 44, 69, -29, -66], + [90, 1030, 44, 69, -29, -66], + [135, 1030, 44, 69, -29, -66], + [180, 1030, 44, 69, -29, -66], + [225, 1030, 44, 69, -29, -66], + [270, 1030, 44, 69, -29, -66], + [315, 1030, 44, 69, -29, -66], + [360, 1030, 44, 69, -29, -66], + [405, 1030, 44, 69, -29, -66], + [450, 1030, 44, 69, -29, -66], + [495, 1030, 44, 69, -29, -66], + [540, 1030, 44, 69, -29, -66], + [585, 1030, 44, 69, -29, -66], + [630, 1030, 44, 69, -29, -66], + [675, 1030, 44, 69, -29, -66], + [720, 1030, 44, 69, -29, -66], + [765, 1030, 44, 69, -29, -66], + [810, 1030, 44, 69, -29, -66], + [855, 1030, 44, 69, -29, -66], + [900, 1030, 44, 69, -29, -66], + [945, 1030, 44, 69, -29, -66], + [990, 1030, 44, 69, -29, -66], + [1035, 1030, 44, 69, -29, -66], + [1080, 1030, 44, 69, -29, -66], + [1125, 1030, 44, 69, -29, -66] + ], + [ + [1170, 1030, 83, 66, -70, -70], + [1254, 1030, 83, 66, -70, -70], + [1338, 1030, 83, 66, -70, -70], + [1422, 1030, 83, 66, -70, -70], + [1506, 1030, 83, 66, -70, -70], + [1590, 1030, 83, 66, -70, -70], + [1674, 1030, 83, 66, -70, -70], + [1758, 1030, 83, 66, -70, -70], + [1842, 1030, 83, 66, -70, -70], + [1926, 1030, 83, 66, -70, -70], + [2010, 1030, 83, 66, -70, -70], + [2094, 1030, 83, 66, -70, -70], + [2178, 1030, 83, 66, -70, -70], + [2262, 1030, 83, 66, -70, -70], + [2346, 1030, 83, 66, -70, -70], + [2430, 1030, 83, 66, -70, -70], + [2514, 1030, 83, 66, -70, -70], + [2598, 1030, 83, 66, -70, -70], + [2682, 1030, 83, 66, -70, -70], + [2766, 1030, 83, 66, -70, -70], + [2850, 1030, 83, 66, -70, -70], + [2934, 1030, 83, 66, -70, -70], + [3018, 1030, 83, 66, -70, -70], + [3102, 1030, 83, 66, -70, -70], + [3186, 1030, 83, 66, -70, -70], + [3270, 1030, 83, 66, -70, -70], + [3354, 1030, 83, 66, -70, -70], + [3438, 1030, 83, 66, -70, -70], + [3522, 1030, 83, 66, -70, -70], + [3606, 1030, 83, 66, -70, -70] + ], + [ + [3690, 1030, 119, 49, -99, -67], + [3810, 1030, 119, 49, -99, -67], + [3930, 1030, 119, 49, -99, -67], + [0, 1100, 119, 49, -99, -67], + [120, 1100, 119, 49, -99, -67], + [240, 1100, 119, 49, -99, -67], + [360, 1100, 119, 49, -99, -67], + [480, 1100, 119, 49, -99, -67], + [600, 1100, 119, 49, -99, -67], + [720, 1100, 119, 49, -99, -67], + [840, 1100, 119, 49, -99, -67], + [960, 1100, 119, 49, -99, -67], + [1080, 1100, 119, 49, -99, -67], + [1200, 1100, 119, 49, -99, -67], + [1320, 1100, 119, 49, -99, -67], + [1440, 1100, 119, 49, -99, -67], + [1560, 1100, 119, 49, -99, -67], + [1680, 1100, 119, 49, -99, -67], + [1800, 1100, 119, 49, -99, -67], + [1920, 1100, 119, 49, -99, -67], + [2040, 1100, 119, 49, -99, -67], + [2160, 1100, 119, 49, -99, -67], + [2280, 1100, 119, 49, -99, -67], + [2400, 1100, 119, 49, -99, -67], + [2520, 1100, 119, 49, -99, -67], + [2640, 1100, 119, 49, -99, -67], + [2760, 1100, 119, 49, -99, -67], + [2880, 1100, 119, 49, -99, -67], + [3000, 1100, 119, 49, -99, -67], + [3120, 1100, 119, 49, -99, -67] + ], + [ + [3240, 1100, 135, 33, -116, -67], + [3376, 1100, 135, 33, -116, -67], + [3512, 1100, 135, 33, -116, -67], + [3648, 1100, 135, 33, -116, -67], + [3784, 1100, 135, 33, -116, -67], + [3920, 1100, 135, 33, -116, -67], + [0, 1150, 135, 33, -116, -67], + [136, 1150, 135, 33, -116, -67], + [272, 1150, 135, 33, -116, -67], + [408, 1150, 135, 33, -116, -67], + [544, 1150, 135, 33, -116, -67], + [680, 1150, 135, 33, -116, -67], + [816, 1150, 135, 33, -116, -67], + [952, 1150, 135, 33, -116, -67], + [1088, 1150, 135, 33, -116, -67], + [1224, 1150, 135, 33, -116, -67], + [1360, 1150, 135, 33, -116, -67], + [1496, 1150, 135, 33, -116, -67], + [1632, 1150, 135, 33, -116, -67], + [1768, 1150, 135, 33, -116, -67], + [1904, 1150, 135, 33, -116, -67], + [2040, 1150, 135, 33, -116, -67], + [2176, 1150, 135, 33, -116, -67], + [2312, 1150, 135, 33, -116, -67], + [2448, 1150, 135, 33, -116, -67], + [2584, 1150, 135, 33, -116, -67], + [2720, 1150, 135, 33, -116, -67], + [2856, 1150, 135, 33, -116, -67], + [2992, 1150, 135, 33, -116, -67], + [3128, 1150, 135, 33, -116, -67] + ], + [ + [3264, 1150, 137, 33, -116, -70], + [3402, 1150, 137, 33, -116, -70], + [3540, 1150, 137, 33, -116, -70], + [3678, 1150, 137, 33, -116, -70], + [3816, 1150, 137, 33, -116, -70], + [3954, 1150, 137, 33, -116, -70], + [0, 1184, 137, 33, -116, -70], + [138, 1184, 137, 33, -116, -70], + [276, 1184, 137, 33, -116, -70], + [414, 1184, 137, 33, -116, -70], + [552, 1184, 137, 33, -116, -70], + [690, 1184, 137, 33, -116, -70], + [828, 1184, 137, 33, -116, -70], + [966, 1184, 137, 33, -116, -70], + [1104, 1184, 137, 33, -116, -70], + [1242, 1184, 137, 33, -116, -70], + [1380, 1184, 137, 33, -116, -70], + [1518, 1184, 137, 33, -116, -70], + [1656, 1184, 137, 33, -116, -70], + [1794, 1184, 137, 33, -116, -70], + [1932, 1184, 137, 33, -116, -70], + [2070, 1184, 137, 33, -116, -70], + [2208, 1184, 137, 33, -116, -70], + [2346, 1184, 137, 33, -116, -70], + [2484, 1184, 137, 33, -116, -70], + [2622, 1184, 137, 33, -116, -70], + [2760, 1184, 137, 33, -116, -70], + [2898, 1184, 137, 33, -116, -70], + [3036, 1184, 137, 33, -116, -70], + [3174, 1184, 137, 33, -116, -70] + ], + [ + [3312, 1184, 121, 47, -99, -86], + [3434, 1184, 121, 47, -99, -86], + [3556, 1184, 121, 47, -99, -86], + [3678, 1184, 121, 47, -99, -86], + [3800, 1184, 121, 47, -99, -86], + [3922, 1184, 121, 47, -99, -86], + [0, 1232, 121, 47, -99, -86], + [122, 1232, 121, 47, -99, -86], + [244, 1232, 121, 47, -99, -86], + [366, 1232, 121, 47, -99, -86], + [488, 1232, 121, 47, -99, -86], + [610, 1232, 121, 47, -99, -86], + [732, 1232, 121, 47, -99, -86], + [854, 1232, 121, 47, -99, -86], + [976, 1232, 121, 47, -99, -86], + [1098, 1232, 121, 47, -99, -86], + [1220, 1232, 121, 47, -99, -86], + [1342, 1232, 121, 47, -99, -86], + [1464, 1232, 121, 47, -99, -86], + [1586, 1232, 121, 47, -99, -86], + [1708, 1232, 121, 47, -99, -86], + [1830, 1232, 121, 47, -99, -86], + [1952, 1232, 121, 47, -99, -86], + [2074, 1232, 121, 47, -99, -86], + [2196, 1232, 121, 47, -99, -86], + [2318, 1232, 121, 47, -99, -86], + [2440, 1232, 121, 47, -99, -86], + [2562, 1232, 121, 47, -99, -86], + [2684, 1232, 121, 47, -99, -86], + [2806, 1232, 121, 47, -99, -86] + ], + [ + [2928, 1232, 86, 66, -68, -100], + [3015, 1232, 86, 66, -68, -100], + [3102, 1232, 86, 66, -68, -100], + [3189, 1232, 86, 66, -68, -100], + [3276, 1232, 86, 66, -68, -100], + [3363, 1232, 86, 66, -68, -100], + [3450, 1232, 86, 66, -68, -100], + [3537, 1232, 86, 66, -68, -100], + [3624, 1232, 86, 66, -68, -100], + [3711, 1232, 86, 66, -68, -100], + [3798, 1232, 86, 66, -68, -100], + [3885, 1232, 86, 66, -68, -100], + [3972, 1232, 86, 66, -68, -100], + [0, 1299, 86, 66, -68, -100], + [87, 1299, 86, 66, -68, -100], + [174, 1299, 86, 66, -68, -100], + [261, 1299, 86, 66, -68, -100], + [348, 1299, 86, 66, -68, -100], + [435, 1299, 86, 66, -68, -100], + [522, 1299, 86, 66, -68, -100], + [609, 1299, 86, 66, -68, -100], + [696, 1299, 86, 66, -68, -100], + [783, 1299, 86, 66, -68, -100], + [870, 1299, 86, 66, -68, -100], + [957, 1299, 86, 66, -68, -100], + [1044, 1299, 86, 66, -68, -100], + [1131, 1299, 86, 66, -68, -100], + [1218, 1299, 86, 66, -68, -100], + [1305, 1299, 86, 66, -68, -100], + [1392, 1299, 86, 66, -68, -100] + ], + [ + [1479, 1299, 40, 70, -25, -109], + [1520, 1299, 40, 70, -25, -109], + [1561, 1299, 40, 70, -25, -109], + [1602, 1299, 40, 70, -25, -109], + [1643, 1299, 40, 70, -25, -109], + [1684, 1299, 40, 70, -25, -109], + [1725, 1299, 40, 70, -25, -109], + [1766, 1299, 40, 70, -25, -109], + [1807, 1299, 40, 70, -25, -109], + [1848, 1299, 40, 70, -25, -109], + [1889, 1299, 40, 70, -25, -109], + [1930, 1299, 40, 70, -25, -109], + [1971, 1299, 40, 70, -25, -109], + [2012, 1299, 40, 70, -25, -109], + [2053, 1299, 40, 70, -25, -109], + [2094, 1299, 40, 70, -25, -109], + [2135, 1299, 40, 70, -25, -109], + [2176, 1299, 40, 70, -25, -109], + [2217, 1299, 40, 70, -25, -109], + [2258, 1299, 40, 70, -25, -109], + [2299, 1299, 40, 70, -25, -109], + [2340, 1299, 40, 70, -25, -109], + [2381, 1299, 40, 70, -25, -109], + [2422, 1299, 40, 70, -25, -109], + [2463, 1299, 40, 70, -25, -109], + [2504, 1299, 40, 70, -25, -109], + [2545, 1299, 40, 70, -25, -109], + [2586, 1299, 40, 70, -25, -109], + [2627, 1299, 40, 70, -25, -109], + [2668, 1299, 40, 70, -25, -109] + ] + ], +} + +export const HOLYBOLT_META: MissileMeta = { + name: "holybolt", + celFile: "HolyBoltMissile", + width: 512, + height: 137, + directions: 1, + framesPerDirection: 16, + animSpeed: 16, + groups: [ + [ + [0, 0, 79, 45, -39, -59], + [80, 0, 79, 45, -39, -59], + [160, 0, 79, 45, -39, -59], + [240, 0, 79, 45, -39, -59], + [320, 0, 79, 45, -39, -59], + [400, 0, 79, 45, -39, -59], + [0, 46, 79, 45, -39, -59], + [80, 46, 79, 45, -39, -59], + [160, 46, 79, 45, -39, -59], + [240, 46, 79, 45, -39, -59], + [320, 46, 79, 45, -39, -59], + [400, 46, 79, 45, -39, -59], + [0, 92, 79, 45, -39, -59], + [80, 92, 79, 45, -39, -59], + [160, 92, 79, 45, -39, -59], + [240, 92, 79, 45, -39, -59] + ] + ], +} + +export const BLESSEDHAMMER_META: MissileMeta = { + name: "blessedhammer", + celFile: "blessedhammer", + width: 512, + height: 192, + directions: 16, + framesPerDirection: 6, + animSpeed: 16, + groups: [ + [ + [0, 0, 27, 38, -13, -56], + [28, 0, 27, 38, -13, -56], + [56, 0, 27, 38, -13, -56], + [84, 0, 27, 38, -13, -56], + [112, 0, 27, 38, -13, -56], + [140, 0, 27, 38, -13, -56] + ], + [ + [168, 0, 26, 33, -13, -53], + [195, 0, 26, 33, -13, -53], + [222, 0, 26, 33, -13, -53], + [249, 0, 26, 33, -13, -53], + [276, 0, 26, 33, -13, -53], + [303, 0, 26, 33, -13, -53] + ], + [ + [330, 0, 27, 33, -14, -54], + [358, 0, 27, 33, -14, -54], + [386, 0, 27, 33, -14, -54], + [414, 0, 27, 33, -14, -54], + [442, 0, 27, 33, -14, -54], + [470, 0, 27, 33, -14, -54] + ], + [ + [0, 39, 27, 38, -13, -56], + [28, 39, 27, 38, -13, -56], + [56, 39, 27, 38, -13, -56], + [84, 39, 27, 38, -13, -56], + [112, 39, 27, 38, -13, -56], + [140, 39, 27, 38, -13, -56] + ], + [ + [168, 39, 7, 38, -3, -56], + [176, 39, 7, 38, -3, -56], + [184, 39, 7, 38, -3, -56], + [192, 39, 7, 38, -3, -56], + [200, 39, 7, 38, -3, -56], + [208, 39, 7, 38, -3, -56] + ], + [ + [216, 39, 36, 35, -18, -54], + [253, 39, 36, 35, -18, -54], + [290, 39, 36, 35, -18, -54], + [327, 39, 36, 35, -18, -54], + [364, 39, 36, 35, -18, -54], + [401, 39, 36, 35, -18, -54] + ], + [ + [438, 39, 7, 32, -4, -53], + [446, 39, 7, 32, -4, -53], + [454, 39, 7, 32, -4, -53], + [462, 39, 7, 32, -4, -53], + [470, 39, 7, 32, -4, -53], + [478, 39, 7, 32, -4, -53] + ], + [ + [0, 78, 36, 35, -18, -55], + [37, 78, 36, 35, -18, -55], + [74, 78, 36, 35, -18, -55], + [111, 78, 36, 35, -18, -55], + [148, 78, 36, 35, -18, -55], + [185, 78, 36, 35, -18, -55] + ], + [ + [222, 78, 16, 38, -8, -56], + [239, 78, 16, 38, -8, -56], + [256, 78, 16, 38, -8, -56], + [273, 78, 16, 38, -8, -56], + [290, 78, 16, 38, -8, -56], + [307, 78, 16, 38, -8, -56] + ], + [ + [324, 78, 34, 36, -17, -55], + [359, 78, 34, 36, -17, -55], + [394, 78, 34, 36, -17, -55], + [429, 78, 34, 36, -17, -55], + [464, 78, 34, 36, -17, -55], + [0, 117, 34, 36, -17, -55] + ], + [ + [35, 117, 34, 34, -17, -54], + [70, 117, 34, 34, -17, -54], + [105, 117, 34, 34, -17, -54], + [140, 117, 34, 34, -17, -54], + [175, 117, 34, 34, -17, -54], + [210, 117, 34, 34, -17, -54] + ], + [ + [245, 117, 16, 32, -8, -53], + [262, 117, 16, 32, -8, -53], + [279, 117, 16, 32, -8, -53], + [296, 117, 16, 32, -8, -53], + [313, 117, 16, 32, -8, -53], + [330, 117, 16, 32, -8, -53] + ], + [ + [347, 117, 16, 32, -9, -53], + [364, 117, 16, 32, -9, -53], + [381, 117, 16, 32, -9, -53], + [398, 117, 16, 32, -9, -53], + [415, 117, 16, 32, -9, -53], + [432, 117, 16, 32, -9, -53] + ], + [ + [449, 117, 33, 34, -17, -54], + [0, 154, 33, 34, -17, -54], + [34, 154, 33, 34, -17, -54], + [68, 154, 33, 34, -17, -54], + [102, 154, 33, 34, -17, -54], + [136, 154, 33, 34, -17, -54] + ], + [ + [170, 154, 34, 36, -17, -55], + [205, 154, 34, 36, -17, -55], + [240, 154, 34, 36, -17, -55], + [275, 154, 34, 36, -17, -55], + [310, 154, 34, 36, -17, -55], + [345, 154, 34, 36, -17, -55] + ], + [ + [380, 154, 16, 38, -7, -56], + [397, 154, 16, 38, -7, -56], + [414, 154, 16, 38, -7, -56], + [431, 154, 16, 38, -7, -56], + [448, 154, 16, 38, -7, -56], + [465, 154, 16, 38, -7, -56] + ] + ], +} + +export const MAGICARROW_META: MissileMeta = { + name: "magicarrow", + celFile: "SafeArrow", + width: 1024, + height: 287, + directions: 32, + framesPerDirection: 8, + animSpeed: 16, + groups: [ + [ + [0, 0, 41, 24, -18, -60], + [42, 0, 41, 24, -18, -60], + [84, 0, 41, 24, -18, -60], + [126, 0, 41, 24, -18, -60], + [168, 0, 41, 24, -18, -60], + [210, 0, 41, 24, -18, -60], + [252, 0, 41, 24, -18, -60], + [294, 0, 41, 24, -18, -60] + ], + [ + [336, 0, 40, 25, -18, -58], + [377, 0, 40, 25, -18, -58], + [418, 0, 40, 25, -18, -58], + [459, 0, 40, 25, -18, -58], + [500, 0, 40, 25, -18, -58], + [541, 0, 40, 25, -18, -58], + [582, 0, 40, 25, -18, -58], + [623, 0, 40, 25, -18, -58] + ], + [ + [664, 0, 40, 25, -22, -58], + [705, 0, 40, 25, -22, -58], + [746, 0, 40, 25, -22, -58], + [787, 0, 40, 25, -22, -58], + [828, 0, 40, 25, -22, -58], + [869, 0, 40, 25, -22, -58], + [910, 0, 40, 25, -22, -58], + [951, 0, 40, 25, -22, -58] + ], + [ + [0, 26, 41, 24, -23, -60], + [42, 26, 41, 24, -23, -60], + [84, 26, 41, 24, -23, -60], + [126, 26, 41, 24, -23, -60], + [168, 26, 41, 24, -23, -60], + [210, 26, 41, 24, -23, -60], + [252, 26, 41, 24, -23, -60], + [294, 26, 41, 24, -23, -60] + ], + [ + [336, 26, 18, 31, -9, -64], + [355, 26, 18, 31, -9, -64], + [374, 26, 18, 31, -9, -64], + [393, 26, 18, 31, -9, -64], + [412, 26, 18, 31, -9, -64], + [431, 26, 18, 31, -9, -64], + [450, 26, 18, 31, -9, -64], + [469, 26, 18, 31, -9, -64] + ], + [ + [488, 26, 53, 17, -23, -55], + [542, 26, 53, 17, -23, -55], + [596, 26, 53, 17, -23, -55], + [650, 26, 53, 17, -23, -55], + [704, 26, 53, 17, -23, -55], + [758, 26, 53, 17, -23, -55], + [812, 26, 53, 17, -23, -55], + [866, 26, 53, 17, -23, -55] + ], + [ + [920, 26, 18, 30, -9, -60], + [939, 26, 18, 30, -9, -60], + [958, 26, 18, 30, -9, -60], + [977, 26, 18, 30, -9, -60], + [996, 26, 18, 30, -9, -60], + [0, 58, 18, 30, -9, -60], + [19, 58, 18, 30, -9, -60], + [38, 58, 18, 30, -9, -60] + ], + [ + [57, 58, 51, 17, -29, -55], + [109, 58, 51, 17, -29, -55], + [161, 58, 51, 17, -29, -55], + [213, 58, 51, 17, -29, -55], + [265, 58, 51, 17, -29, -55], + [317, 58, 51, 17, -29, -55], + [369, 58, 51, 17, -29, -55], + [421, 58, 51, 17, -29, -55] + ], + [ + [473, 58, 26, 28, -12, -62], + [500, 58, 26, 28, -12, -62], + [527, 58, 26, 28, -12, -62], + [554, 58, 26, 28, -12, -62], + [581, 58, 26, 28, -12, -62], + [608, 58, 26, 28, -12, -62], + [635, 58, 26, 28, -12, -62], + [662, 58, 26, 28, -12, -62] + ], + [ + [689, 58, 50, 19, -22, -57], + [740, 58, 50, 19, -22, -57], + [791, 58, 50, 19, -22, -57], + [842, 58, 50, 19, -22, -57], + [893, 58, 50, 19, -22, -57], + [944, 58, 50, 19, -22, -57], + [0, 89, 50, 19, -22, -57], + [51, 89, 50, 19, -22, -57] + ], + [ + [102, 89, 48, 20, -21, -56], + [151, 89, 48, 20, -21, -56], + [200, 89, 48, 20, -21, -56], + [249, 89, 48, 20, -21, -56], + [298, 89, 48, 20, -21, -56], + [347, 89, 48, 20, -21, -56], + [396, 89, 48, 20, -21, -56], + [445, 89, 48, 20, -21, -56] + ], + [ + [494, 89, 27, 28, -12, -59], + [522, 89, 27, 28, -12, -59], + [550, 89, 27, 28, -12, -59], + [578, 89, 27, 28, -12, -59], + [606, 89, 27, 28, -12, -59], + [634, 89, 27, 28, -12, -59], + [662, 89, 27, 28, -12, -59], + [690, 89, 27, 28, -12, -59] + ], + [ + [718, 89, 27, 28, -15, -59], + [746, 89, 27, 28, -15, -59], + [774, 89, 27, 28, -15, -59], + [802, 89, 27, 28, -15, -59], + [830, 89, 27, 28, -15, -59], + [858, 89, 27, 28, -15, -59], + [886, 89, 27, 28, -15, -59], + [914, 89, 27, 28, -15, -59] + ], + [ + [942, 89, 50, 20, -28, -56], + [0, 118, 50, 20, -28, -56], + [51, 118, 50, 20, -28, -56], + [102, 118, 50, 20, -28, -56], + [153, 118, 50, 20, -28, -56], + [204, 118, 50, 20, -28, -56], + [255, 118, 50, 20, -28, -56], + [306, 118, 50, 20, -28, -56] + ], + [ + [357, 118, 50, 19, -28, -57], + [408, 118, 50, 19, -28, -57], + [459, 118, 50, 19, -28, -57], + [510, 118, 50, 19, -28, -57], + [561, 118, 50, 19, -28, -57], + [612, 118, 50, 19, -28, -57], + [663, 118, 50, 19, -28, -57], + [714, 118, 50, 19, -28, -57] + ], + [ + [765, 118, 27, 28, -15, -62], + [793, 118, 27, 28, -15, -62], + [821, 118, 27, 28, -15, -62], + [849, 118, 27, 28, -15, -62], + [877, 118, 27, 28, -15, -62], + [905, 118, 27, 28, -15, -62], + [933, 118, 27, 28, -15, -62], + [961, 118, 27, 28, -15, -62] + ], + [ + [989, 118, 20, 30, -9, -63], + [0, 149, 20, 30, -9, -63], + [21, 149, 20, 30, -9, -63], + [42, 149, 20, 30, -9, -63], + [63, 149, 20, 30, -9, -63], + [84, 149, 20, 30, -9, -63], + [105, 149, 20, 30, -9, -63], + [126, 149, 20, 30, -9, -63] + ], + [ + [147, 149, 33, 26, -15, -61], + [181, 149, 33, 26, -15, -61], + [215, 149, 33, 26, -15, -61], + [249, 149, 33, 26, -15, -61], + [283, 149, 33, 26, -15, -61], + [317, 149, 33, 26, -15, -61], + [351, 149, 33, 26, -15, -61], + [385, 149, 33, 26, -15, -61] + ], + [ + [419, 149, 45, 22, -20, -59], + [465, 149, 45, 22, -20, -59], + [511, 149, 45, 22, -20, -59], + [557, 149, 45, 22, -20, -59], + [603, 149, 45, 22, -20, -59], + [649, 149, 45, 22, -20, -59], + [695, 149, 45, 22, -20, -59], + [741, 149, 45, 22, -20, -59] + ], + [ + [787, 149, 51, 18, -22, -56], + [839, 149, 51, 18, -22, -56], + [891, 149, 51, 18, -22, -56], + [943, 149, 51, 18, -22, -56], + [0, 180, 51, 18, -22, -56], + [52, 180, 51, 18, -22, -56], + [104, 180, 51, 18, -22, -56], + [156, 180, 51, 18, -22, -56] + ], + [ + [208, 180, 52, 17, -23, -55], + [261, 180, 52, 17, -23, -55], + [314, 180, 52, 17, -23, -55], + [367, 180, 52, 17, -23, -55], + [420, 180, 52, 17, -23, -55], + [473, 180, 52, 17, -23, -55], + [526, 180, 52, 17, -23, -55], + [579, 180, 52, 17, -23, -55] + ], + [ + [632, 180, 45, 22, -20, -57], + [678, 180, 45, 22, -20, -57], + [724, 180, 45, 22, -20, -57], + [770, 180, 45, 22, -20, -57], + [816, 180, 45, 22, -20, -57], + [862, 180, 45, 22, -20, -57], + [908, 180, 45, 22, -20, -57], + [954, 180, 45, 22, -20, -57] + ], + [ + [0, 203, 33, 27, -15, -59], + [34, 203, 33, 27, -15, -59], + [68, 203, 33, 27, -15, -59], + [102, 203, 33, 27, -15, -59], + [136, 203, 33, 27, -15, -59], + [170, 203, 33, 27, -15, -59], + [204, 203, 33, 27, -15, -59], + [238, 203, 33, 27, -15, -59] + ], + [ + [272, 203, 20, 29, -9, -60], + [293, 203, 20, 29, -9, -60], + [314, 203, 20, 29, -9, -60], + [335, 203, 20, 29, -9, -60], + [356, 203, 20, 29, -9, -60], + [377, 203, 20, 29, -9, -60], + [398, 203, 20, 29, -9, -60], + [419, 203, 20, 29, -9, -60] + ], + [ + [440, 203, 20, 30, -11, -60], + [461, 203, 20, 30, -11, -60], + [482, 203, 20, 30, -11, -60], + [503, 203, 20, 30, -11, -60], + [524, 203, 20, 30, -11, -60], + [545, 203, 20, 30, -11, -60], + [566, 203, 20, 30, -11, -60], + [587, 203, 20, 30, -11, -60] + ], + [ + [608, 203, 34, 27, -19, -59], + [643, 203, 34, 27, -19, -59], + [678, 203, 34, 27, -19, -59], + [713, 203, 34, 27, -19, -59], + [748, 203, 34, 27, -19, -59], + [783, 203, 34, 27, -19, -59], + [818, 203, 34, 27, -19, -59], + [853, 203, 34, 27, -19, -59] + ], + [ + [888, 203, 46, 22, -26, -57], + [935, 203, 46, 22, -26, -57], + [0, 234, 46, 22, -26, -57], + [47, 234, 46, 22, -26, -57], + [94, 234, 46, 22, -26, -57], + [141, 234, 46, 22, -26, -57], + [188, 234, 46, 22, -26, -57], + [235, 234, 46, 22, -26, -57] + ], + [ + [282, 234, 51, 18, -29, -55], + [334, 234, 51, 18, -29, -55], + [386, 234, 51, 18, -29, -55], + [438, 234, 51, 18, -29, -55], + [490, 234, 51, 18, -29, -55], + [542, 234, 51, 18, -29, -55], + [594, 234, 51, 18, -29, -55], + [646, 234, 51, 18, -29, -55] + ], + [ + [698, 234, 52, 18, -29, -56], + [751, 234, 52, 18, -29, -56], + [804, 234, 52, 18, -29, -56], + [857, 234, 52, 18, -29, -56], + [910, 234, 52, 18, -29, -56], + [963, 234, 52, 18, -29, -56], + [0, 257, 52, 18, -29, -56], + [53, 257, 52, 18, -29, -56] + ], + [ + [106, 257, 46, 22, -26, -59], + [153, 257, 46, 22, -26, -59], + [200, 257, 46, 22, -26, -59], + [247, 257, 46, 22, -26, -59], + [294, 257, 46, 22, -26, -59], + [341, 257, 46, 22, -26, -59], + [388, 257, 46, 22, -26, -59], + [435, 257, 46, 22, -26, -59] + ], + [ + [482, 257, 33, 26, -18, -61], + [516, 257, 33, 26, -18, -61], + [550, 257, 33, 26, -18, -61], + [584, 257, 33, 26, -18, -61], + [618, 257, 33, 26, -18, -61], + [652, 257, 33, 26, -18, -61], + [686, 257, 33, 26, -18, -61], + [720, 257, 33, 26, -18, -61] + ], + [ + [754, 257, 20, 30, -11, -63], + [775, 257, 20, 30, -11, -63], + [796, 257, 20, 30, -11, -63], + [817, 257, 20, 30, -11, -63], + [838, 257, 20, 30, -11, -63], + [859, 257, 20, 30, -11, -63], + [880, 257, 20, 30, -11, -63], + [901, 257, 20, 30, -11, -63] + ] + ], +} + +export const FIREARROW_META: MissileMeta = { + name: "firearrow", + celFile: "FireArrow", + width: 512, + height: 355, + directions: 32, + framesPerDirection: 8, + animSpeed: 16, + groups: [ + [ + [0, 0, 32, 18, -16, -56], + [33, 0, 32, 18, -16, -56], + [66, 0, 32, 18, -16, -56], + [99, 0, 32, 18, -16, -56], + [132, 0, 32, 18, -16, -56], + [165, 0, 32, 18, -16, -56], + [198, 0, 32, 18, -16, -56], + [231, 0, 32, 18, -16, -56] + ], + [ + [264, 0, 32, 20, -16, -56], + [297, 0, 32, 20, -16, -56], + [330, 0, 32, 20, -16, -56], + [363, 0, 32, 20, -16, -56], + [396, 0, 32, 20, -16, -56], + [429, 0, 32, 20, -16, -56], + [462, 0, 32, 20, -16, -56], + [0, 21, 32, 20, -16, -56] + ], + [ + [33, 21, 32, 20, -16, -56], + [66, 21, 32, 20, -16, -56], + [99, 21, 32, 20, -16, -56], + [132, 21, 32, 20, -16, -56], + [165, 21, 32, 20, -16, -56], + [198, 21, 32, 20, -16, -56], + [231, 21, 32, 20, -16, -56], + [264, 21, 32, 20, -16, -56] + ], + [ + [297, 21, 32, 19, -16, -57], + [330, 21, 32, 19, -16, -57], + [363, 21, 32, 19, -16, -57], + [396, 21, 32, 19, -16, -57], + [429, 21, 32, 19, -16, -57], + [462, 21, 32, 19, -16, -57], + [0, 42, 32, 19, -16, -57], + [33, 42, 32, 19, -16, -57] + ], + [ + [66, 42, 10, 24, -5, -59], + [77, 42, 10, 24, -5, -59], + [88, 42, 10, 24, -5, -59], + [99, 42, 10, 24, -5, -59], + [110, 42, 10, 24, -5, -59], + [121, 42, 10, 24, -5, -59], + [132, 42, 10, 24, -5, -59], + [143, 42, 10, 24, -5, -59] + ], + [ + [154, 42, 41, 10, -22, -52], + [196, 42, 41, 10, -22, -52], + [238, 42, 41, 10, -22, -52], + [280, 42, 41, 10, -22, -52], + [322, 42, 41, 10, -22, -52], + [364, 42, 41, 10, -22, -52], + [406, 42, 41, 10, -22, -52], + [448, 42, 41, 10, -22, -52] + ], + [ + [490, 42, 10, 25, -5, -59], + [501, 42, 10, 25, -5, -59], + [0, 68, 10, 25, -5, -59], + [11, 68, 10, 25, -5, -59], + [22, 68, 10, 25, -5, -59], + [33, 68, 10, 25, -5, -59], + [44, 68, 10, 25, -5, -59], + [55, 68, 10, 25, -5, -59] + ], + [ + [66, 68, 41, 10, -19, -52], + [108, 68, 41, 10, -19, -52], + [150, 68, 41, 10, -19, -52], + [192, 68, 41, 10, -19, -52], + [234, 68, 41, 10, -19, -52], + [276, 68, 41, 10, -19, -52], + [318, 68, 41, 10, -19, -52], + [360, 68, 41, 10, -19, -52] + ], + [ + [402, 68, 21, 22, -10, -58], + [424, 68, 21, 22, -10, -58], + [446, 68, 21, 22, -10, -58], + [468, 68, 21, 22, -10, -58], + [490, 68, 21, 22, -10, -58], + [0, 94, 21, 22, -10, -58], + [22, 94, 21, 22, -10, -58], + [44, 94, 21, 22, -10, -58] + ], + [ + [66, 94, 38, 14, -20, -54], + [105, 94, 38, 14, -20, -54], + [144, 94, 38, 14, -20, -54], + [183, 94, 38, 14, -20, -54], + [222, 94, 38, 14, -20, -54], + [261, 94, 38, 14, -20, -54], + [300, 94, 38, 14, -20, -54], + [339, 94, 38, 14, -20, -54] + ], + [ + [378, 94, 38, 14, -20, -53], + [417, 94, 38, 14, -20, -53], + [456, 94, 38, 14, -20, -53], + [0, 117, 38, 14, -20, -53], + [39, 117, 38, 14, -20, -53], + [78, 117, 38, 14, -20, -53], + [117, 117, 38, 14, -20, -53], + [156, 117, 38, 14, -20, -53] + ], + [ + [195, 117, 21, 23, -10, -58], + [217, 117, 21, 23, -10, -58], + [239, 117, 21, 23, -10, -58], + [261, 117, 21, 23, -10, -58], + [283, 117, 21, 23, -10, -58], + [305, 117, 21, 23, -10, -58], + [327, 117, 21, 23, -10, -58], + [349, 117, 21, 23, -10, -58] + ], + [ + [371, 117, 22, 23, -12, -58], + [394, 117, 22, 23, -12, -58], + [417, 117, 22, 23, -12, -58], + [440, 117, 22, 23, -12, -58], + [463, 117, 22, 23, -12, -58], + [486, 117, 22, 23, -12, -58], + [0, 141, 22, 23, -12, -58], + [23, 141, 22, 23, -12, -58] + ], + [ + [46, 141, 38, 14, -18, -53], + [85, 141, 38, 14, -18, -53], + [124, 141, 38, 14, -18, -53], + [163, 141, 38, 14, -18, -53], + [202, 141, 38, 14, -18, -53], + [241, 141, 38, 14, -18, -53], + [280, 141, 38, 14, -18, -53], + [319, 141, 38, 14, -18, -53] + ], + [ + [358, 141, 38, 15, -18, -55], + [397, 141, 38, 15, -18, -55], + [436, 141, 38, 15, -18, -55], + [0, 165, 38, 15, -18, -55], + [39, 165, 38, 15, -18, -55], + [78, 165, 38, 15, -18, -55], + [117, 165, 38, 15, -18, -55], + [156, 165, 38, 15, -18, -55] + ], + [ + [195, 165, 22, 23, -12, -59], + [218, 165, 22, 23, -12, -59], + [241, 165, 22, 23, -12, -59], + [264, 165, 22, 23, -12, -59], + [287, 165, 22, 23, -12, -59], + [310, 165, 22, 23, -12, -59], + [333, 165, 22, 23, -12, -59], + [356, 165, 22, 23, -12, -59] + ], + [ + [379, 165, 16, 23, -7, -58], + [396, 165, 16, 23, -7, -58], + [413, 165, 16, 23, -7, -58], + [430, 165, 16, 23, -7, -58], + [447, 165, 16, 23, -7, -58], + [464, 165, 16, 23, -7, -58], + [481, 165, 16, 23, -7, -58], + [0, 189, 16, 23, -7, -58] + ], + [ + [17, 189, 27, 20, -13, -57], + [45, 189, 27, 20, -13, -57], + [73, 189, 27, 20, -13, -57], + [101, 189, 27, 20, -13, -57], + [129, 189, 27, 20, -13, -57], + [157, 189, 27, 20, -13, -57], + [185, 189, 27, 20, -13, -57], + [213, 189, 27, 20, -13, -57] + ], + [ + [241, 189, 35, 16, -18, -55], + [277, 189, 35, 16, -18, -55], + [313, 189, 35, 16, -18, -55], + [349, 189, 35, 16, -18, -55], + [385, 189, 35, 16, -18, -55], + [421, 189, 35, 16, -18, -55], + [457, 189, 35, 16, -18, -55], + [0, 213, 35, 16, -18, -55] + ], + [ + [36, 213, 41, 11, -22, -53], + [78, 213, 41, 11, -22, -53], + [120, 213, 41, 11, -22, -53], + [162, 213, 41, 11, -22, -53], + [204, 213, 41, 11, -22, -53], + [246, 213, 41, 11, -22, -53], + [288, 213, 41, 11, -22, -53], + [330, 213, 41, 11, -22, -53] + ], + [ + [372, 213, 41, 12, -22, -52], + [414, 213, 41, 12, -22, -52], + [456, 213, 41, 12, -22, -52], + [0, 230, 41, 12, -22, -52], + [42, 230, 41, 12, -22, -52], + [84, 230, 41, 12, -22, -52], + [126, 230, 41, 12, -22, -52], + [168, 230, 41, 12, -22, -52] + ], + [ + [210, 230, 35, 18, -18, -55], + [246, 230, 35, 18, -18, -55], + [282, 230, 35, 18, -18, -55], + [318, 230, 35, 18, -18, -55], + [354, 230, 35, 18, -18, -55], + [390, 230, 35, 18, -18, -55], + [426, 230, 35, 18, -18, -55], + [462, 230, 35, 18, -18, -55] + ], + [ + [0, 249, 27, 22, -13, -57], + [28, 249, 27, 22, -13, -57], + [56, 249, 27, 22, -13, -57], + [84, 249, 27, 22, -13, -57], + [112, 249, 27, 22, -13, -57], + [140, 249, 27, 22, -13, -57], + [168, 249, 27, 22, -13, -57], + [196, 249, 27, 22, -13, -57] + ], + [ + [224, 249, 16, 24, -7, -58], + [241, 249, 16, 24, -7, -58], + [258, 249, 16, 24, -7, -58], + [275, 249, 16, 24, -7, -58], + [292, 249, 16, 24, -7, -58], + [309, 249, 16, 24, -7, -58], + [326, 249, 16, 24, -7, -58], + [343, 249, 16, 24, -7, -58] + ], + [ + [360, 249, 16, 24, -9, -58], + [377, 249, 16, 24, -9, -58], + [394, 249, 16, 24, -9, -58], + [411, 249, 16, 24, -9, -58], + [428, 249, 16, 24, -9, -58], + [445, 249, 16, 24, -9, -58], + [462, 249, 16, 24, -9, -58], + [479, 249, 16, 24, -9, -58] + ], + [ + [0, 274, 27, 22, -14, -57], + [28, 274, 27, 22, -14, -57], + [56, 274, 27, 22, -14, -57], + [84, 274, 27, 22, -14, -57], + [112, 274, 27, 22, -14, -57], + [140, 274, 27, 22, -14, -57], + [168, 274, 27, 22, -14, -57], + [196, 274, 27, 22, -14, -57] + ], + [ + [224, 274, 35, 18, -17, -55], + [260, 274, 35, 18, -17, -55], + [296, 274, 35, 18, -17, -55], + [332, 274, 35, 18, -17, -55], + [368, 274, 35, 18, -17, -55], + [404, 274, 35, 18, -17, -55], + [440, 274, 35, 18, -17, -55], + [476, 274, 35, 18, -17, -55] + ], + [ + [0, 297, 41, 12, -19, -52], + [42, 297, 41, 12, -19, -52], + [84, 297, 41, 12, -19, -52], + [126, 297, 41, 12, -19, -52], + [168, 297, 41, 12, -19, -52], + [210, 297, 41, 12, -19, -52], + [252, 297, 41, 12, -19, -52], + [294, 297, 41, 12, -19, -52] + ], + [ + [336, 297, 41, 11, -19, -53], + [378, 297, 41, 11, -19, -53], + [420, 297, 41, 11, -19, -53], + [462, 297, 41, 11, -19, -53], + [0, 310, 41, 11, -19, -53], + [42, 310, 41, 11, -19, -53], + [84, 310, 41, 11, -19, -53], + [126, 310, 41, 11, -19, -53] + ], + [ + [168, 310, 35, 17, -17, -56], + [204, 310, 35, 17, -17, -56], + [240, 310, 35, 17, -17, -56], + [276, 310, 35, 17, -17, -56], + [312, 310, 35, 17, -17, -56], + [348, 310, 35, 17, -17, -56], + [384, 310, 35, 17, -17, -56], + [420, 310, 35, 17, -17, -56] + ], + [ + [456, 310, 27, 20, -14, -57], + [484, 310, 27, 20, -14, -57], + [0, 331, 27, 20, -14, -57], + [28, 331, 27, 20, -14, -57], + [56, 331, 27, 20, -14, -57], + [84, 331, 27, 20, -14, -57], + [112, 331, 27, 20, -14, -57], + [140, 331, 27, 20, -14, -57] + ], + [ + [168, 331, 16, 24, -9, -59], + [185, 331, 16, 24, -9, -59], + [202, 331, 16, 24, -9, -59], + [219, 331, 16, 24, -9, -59], + [236, 331, 16, 24, -9, -59], + [253, 331, 16, 24, -9, -59], + [270, 331, 16, 24, -9, -59], + [287, 331, 16, 24, -9, -59] + ] + ], +} + +export const ICEARROW_META: MissileMeta = { + name: "icearrow", + celFile: "IceArrow", + width: 1024, + height: 324, + directions: 32, + framesPerDirection: 8, + animSpeed: 16, + groups: [ + [ + [0, 0, 45, 25, -20, -60], + [46, 0, 45, 25, -20, -60], + [92, 0, 45, 25, -20, -60], + [138, 0, 45, 25, -20, -60], + [184, 0, 45, 25, -20, -60], + [230, 0, 45, 25, -20, -60], + [276, 0, 45, 25, -20, -60], + [322, 0, 45, 25, -20, -60] + ], + [ + [368, 0, 44, 25, -19, -58], + [413, 0, 44, 25, -19, -58], + [458, 0, 44, 25, -19, -58], + [503, 0, 44, 25, -19, -58], + [548, 0, 44, 25, -19, -58], + [593, 0, 44, 25, -19, -58], + [638, 0, 44, 25, -19, -58], + [683, 0, 44, 25, -19, -58] + ], + [ + [728, 0, 45, 25, -25, -58], + [774, 0, 45, 25, -25, -58], + [820, 0, 45, 25, -25, -58], + [866, 0, 45, 25, -25, -58], + [912, 0, 45, 25, -25, -58], + [958, 0, 45, 25, -25, -58], + [0, 26, 45, 25, -25, -58], + [46, 26, 45, 25, -25, -58] + ], + [ + [92, 26, 45, 24, -25, -60], + [138, 26, 45, 24, -25, -60], + [184, 26, 45, 24, -25, -60], + [230, 26, 45, 24, -25, -60], + [276, 26, 45, 24, -25, -60], + [322, 26, 45, 24, -25, -60], + [368, 26, 45, 24, -25, -60], + [414, 26, 45, 24, -25, -60] + ], + [ + [460, 26, 16, 31, -8, -64], + [477, 26, 16, 31, -8, -64], + [494, 26, 16, 31, -8, -64], + [511, 26, 16, 31, -8, -64], + [528, 26, 16, 31, -8, -64], + [545, 26, 16, 31, -8, -64], + [562, 26, 16, 31, -8, -64], + [579, 26, 16, 31, -8, -64] + ], + [ + [596, 26, 61, 15, -27, -54], + [658, 26, 61, 15, -27, -54], + [720, 26, 61, 15, -27, -54], + [782, 26, 61, 15, -27, -54], + [844, 26, 61, 15, -27, -54], + [906, 26, 61, 15, -27, -54], + [0, 58, 61, 15, -27, -54], + [62, 58, 61, 15, -27, -54] + ], + [ + [124, 58, 16, 32, -8, -61], + [141, 58, 16, 32, -8, -61], + [158, 58, 16, 32, -8, -61], + [175, 58, 16, 32, -8, -61], + [192, 58, 16, 32, -8, -61], + [209, 58, 16, 32, -8, -61], + [226, 58, 16, 32, -8, -61], + [243, 58, 16, 32, -8, -61] + ], + [ + [260, 58, 60, 15, -34, -54], + [321, 58, 60, 15, -34, -54], + [382, 58, 60, 15, -34, -54], + [443, 58, 60, 15, -34, -54], + [504, 58, 60, 15, -34, -54], + [565, 58, 60, 15, -34, -54], + [626, 58, 60, 15, -34, -54], + [687, 58, 60, 15, -34, -54] + ], + [ + [748, 58, 27, 30, -12, -63], + [776, 58, 27, 30, -12, -63], + [804, 58, 27, 30, -12, -63], + [832, 58, 27, 30, -12, -63], + [860, 58, 27, 30, -12, -63], + [888, 58, 27, 30, -12, -63], + [916, 58, 27, 30, -12, -63], + [944, 58, 27, 30, -12, -63] + ], + [ + [0, 91, 57, 19, -25, -57], + [58, 91, 57, 19, -25, -57], + [116, 91, 57, 19, -25, -57], + [174, 91, 57, 19, -25, -57], + [232, 91, 57, 19, -25, -57], + [290, 91, 57, 19, -25, -57], + [348, 91, 57, 19, -25, -57], + [406, 91, 57, 19, -25, -57] + ], + [ + [464, 91, 57, 18, -25, -55], + [522, 91, 57, 18, -25, -55], + [580, 91, 57, 18, -25, -55], + [638, 91, 57, 18, -25, -55], + [696, 91, 57, 18, -25, -55], + [754, 91, 57, 18, -25, -55], + [812, 91, 57, 18, -25, -55], + [870, 91, 57, 18, -25, -55] + ], + [ + [928, 91, 27, 30, -12, -60], + [956, 91, 27, 30, -12, -60], + [984, 91, 27, 30, -12, -60], + [0, 122, 27, 30, -12, -60], + [28, 122, 27, 30, -12, -60], + [56, 122, 27, 30, -12, -60], + [84, 122, 27, 30, -12, -60], + [112, 122, 27, 30, -12, -60] + ], + [ + [140, 122, 27, 30, -15, -60], + [168, 122, 27, 30, -15, -60], + [196, 122, 27, 30, -15, -60], + [224, 122, 27, 30, -15, -60], + [252, 122, 27, 30, -15, -60], + [280, 122, 27, 30, -15, -60], + [308, 122, 27, 30, -15, -60], + [336, 122, 27, 30, -15, -60] + ], + [ + [364, 122, 57, 18, -32, -55], + [422, 122, 57, 18, -32, -55], + [480, 122, 57, 18, -32, -55], + [538, 122, 57, 18, -32, -55], + [596, 122, 57, 18, -32, -55], + [654, 122, 57, 18, -32, -55], + [712, 122, 57, 18, -32, -55], + [770, 122, 57, 18, -32, -55] + ], + [ + [828, 122, 57, 19, -32, -57], + [886, 122, 57, 19, -32, -57], + [944, 122, 57, 19, -32, -57], + [0, 153, 57, 19, -32, -57], + [58, 153, 57, 19, -32, -57], + [116, 153, 57, 19, -32, -57], + [174, 153, 57, 19, -32, -57], + [232, 153, 57, 19, -32, -57] + ], + [ + [290, 153, 27, 30, -15, -63], + [318, 153, 27, 30, -15, -63], + [346, 153, 27, 30, -15, -63], + [374, 153, 27, 30, -15, -63], + [402, 153, 27, 30, -15, -63], + [430, 153, 27, 30, -15, -63], + [458, 153, 27, 30, -15, -63], + [486, 153, 27, 30, -15, -63] + ], + [ + [514, 153, 19, 31, -9, -64], + [534, 153, 19, 31, -9, -64], + [554, 153, 19, 31, -9, -64], + [574, 153, 19, 31, -9, -64], + [594, 153, 19, 31, -9, -64], + [614, 153, 19, 31, -9, -64], + [634, 153, 19, 31, -9, -64], + [654, 153, 19, 31, -9, -64] + ], + [ + [674, 153, 36, 28, -16, -62], + [711, 153, 36, 28, -16, -62], + [748, 153, 36, 28, -16, -62], + [785, 153, 36, 28, -16, -62], + [822, 153, 36, 28, -16, -62], + [859, 153, 36, 28, -16, -62], + [896, 153, 36, 28, -16, -62], + [933, 153, 36, 28, -16, -62] + ], + [ + [970, 153, 51, 21, -22, -58], + [0, 185, 51, 21, -22, -58], + [52, 185, 51, 21, -22, -58], + [104, 185, 51, 21, -22, -58], + [156, 185, 51, 21, -22, -58], + [208, 185, 51, 21, -22, -58], + [260, 185, 51, 21, -22, -58], + [312, 185, 51, 21, -22, -58] + ], + [ + [364, 185, 59, 16, -26, -55], + [424, 185, 59, 16, -26, -55], + [484, 185, 59, 16, -26, -55], + [544, 185, 59, 16, -26, -55], + [604, 185, 59, 16, -26, -55], + [664, 185, 59, 16, -26, -55], + [724, 185, 59, 16, -26, -55], + [784, 185, 59, 16, -26, -55] + ], + [ + [844, 185, 59, 16, -26, -54], + [904, 185, 59, 16, -26, -54], + [964, 185, 59, 16, -26, -54], + [0, 207, 59, 16, -26, -54], + [60, 207, 59, 16, -26, -54], + [120, 207, 59, 16, -26, -54], + [180, 207, 59, 16, -26, -54], + [240, 207, 59, 16, -26, -54] + ], + [ + [300, 207, 50, 21, -22, -56], + [351, 207, 50, 21, -22, -56], + [402, 207, 50, 21, -22, -56], + [453, 207, 50, 21, -22, -56], + [504, 207, 50, 21, -22, -56], + [555, 207, 50, 21, -22, -56], + [606, 207, 50, 21, -22, -56], + [657, 207, 50, 21, -22, -56] + ], + [ + [708, 207, 36, 28, -16, -59], + [745, 207, 36, 28, -16, -59], + [782, 207, 36, 28, -16, -59], + [819, 207, 36, 28, -16, -59], + [856, 207, 36, 28, -16, -59], + [893, 207, 36, 28, -16, -59], + [930, 207, 36, 28, -16, -59], + [967, 207, 36, 28, -16, -59] + ], + [ + [1004, 207, 19, 31, -9, -60], + [0, 239, 19, 31, -9, -60], + [20, 239, 19, 31, -9, -60], + [40, 239, 19, 31, -9, -60], + [60, 239, 19, 31, -9, -60], + [80, 239, 19, 31, -9, -60], + [100, 239, 19, 31, -9, -60], + [120, 239, 19, 31, -9, -60] + ], + [ + [140, 239, 19, 31, -10, -60], + [160, 239, 19, 31, -10, -60], + [180, 239, 19, 31, -10, -60], + [200, 239, 19, 31, -10, -60], + [220, 239, 19, 31, -10, -60], + [240, 239, 19, 31, -10, -60], + [260, 239, 19, 31, -10, -60], + [280, 239, 19, 31, -10, -60] + ], + [ + [300, 239, 36, 28, -20, -59], + [337, 239, 36, 28, -20, -59], + [374, 239, 36, 28, -20, -59], + [411, 239, 36, 28, -20, -59], + [448, 239, 36, 28, -20, -59], + [485, 239, 36, 28, -20, -59], + [522, 239, 36, 28, -20, -59], + [559, 239, 36, 28, -20, -59] + ], + [ + [596, 239, 52, 21, -29, -56], + [649, 239, 52, 21, -29, -56], + [702, 239, 52, 21, -29, -56], + [755, 239, 52, 21, -29, -56], + [808, 239, 52, 21, -29, -56], + [861, 239, 52, 21, -29, -56], + [914, 239, 52, 21, -29, -56], + [967, 239, 52, 21, -29, -56] + ], + [ + [0, 271, 59, 16, -33, -54], + [60, 271, 59, 16, -33, -54], + [120, 271, 59, 16, -33, -54], + [180, 271, 59, 16, -33, -54], + [240, 271, 59, 16, -33, -54], + [300, 271, 59, 16, -33, -54], + [360, 271, 59, 16, -33, -54], + [420, 271, 59, 16, -33, -54] + ], + [ + [480, 271, 59, 16, -33, -55], + [540, 271, 59, 16, -33, -55], + [600, 271, 59, 16, -33, -55], + [660, 271, 59, 16, -33, -55], + [720, 271, 59, 16, -33, -55], + [780, 271, 59, 16, -33, -55], + [840, 271, 59, 16, -33, -55], + [900, 271, 59, 16, -33, -55] + ], + [ + [960, 271, 52, 21, -29, -58], + [0, 293, 52, 21, -29, -58], + [53, 293, 52, 21, -29, -58], + [106, 293, 52, 21, -29, -58], + [159, 293, 52, 21, -29, -58], + [212, 293, 52, 21, -29, -58], + [265, 293, 52, 21, -29, -58], + [318, 293, 52, 21, -29, -58] + ], + [ + [371, 293, 36, 28, -20, -62], + [408, 293, 36, 28, -20, -62], + [445, 293, 36, 28, -20, -62], + [482, 293, 36, 28, -20, -62], + [519, 293, 36, 28, -20, -62], + [556, 293, 36, 28, -20, -62], + [593, 293, 36, 28, -20, -62], + [630, 293, 36, 28, -20, -62] + ], + [ + [667, 293, 19, 31, -10, -64], + [687, 293, 19, 31, -10, -64], + [707, 293, 19, 31, -10, -64], + [727, 293, 19, 31, -10, -64], + [747, 293, 19, 31, -10, -64], + [767, 293, 19, 31, -10, -64], + [787, 293, 19, 31, -10, -64], + [807, 293, 19, 31, -10, -64] + ] + ], +} + +export const ARROW_META: MissileMeta = { + name: "arrow", + celFile: "Arrow", + width: 512, + height: 36, + directions: 32, + framesPerDirection: 1, + animSpeed: 16, + groups: [ + [ + [0, 0, 31, 13, -16, -56] + ], + [ + [32, 0, 31, 13, -15, -55] + ], + [ + [64, 0, 30, 14, -15, -55] + ], + [ + [95, 0, 31, 14, -15, -56] + ], + [ + [127, 0, 4, 18, -2, -58] + ], + [ + [132, 0, 42, 5, -22, -52] + ], + [ + [175, 0, 4, 17, -2, -57] + ], + [ + [180, 0, 41, 5, -20, -51] + ], + [ + [222, 0, 18, 17, -9, -58] + ], + [ + [241, 0, 39, 9, -20, -54] + ], + [ + [281, 0, 39, 8, -20, -53] + ], + [ + [321, 0, 18, 16, -8, -57] + ], + [ + [340, 0, 18, 17, -9, -57] + ], + [ + [359, 0, 39, 9, -19, -53] + ], + [ + [399, 0, 39, 8, -19, -53] + ], + [ + [439, 0, 18, 16, -9, -57] + ], + [ + [458, 0, 11, 18, -6, -58] + ], + [ + [470, 0, 25, 15, -13, -57] + ], + [ + [0, 19, 35, 12, -18, -56] + ], + [ + [36, 19, 41, 7, -21, -53] + ], + [ + [78, 19, 41, 6, -21, -52] + ], + [ + [120, 19, 35, 11, -17, -54] + ], + [ + [156, 19, 25, 15, -12, -56] + ], + [ + [182, 19, 11, 17, -5, -57] + ], + [ + [194, 19, 11, 17, -6, -57] + ], + [ + [206, 19, 25, 16, -13, -56] + ], + [ + [232, 19, 35, 12, -17, -54] + ], + [ + [268, 19, 41, 7, -20, -52] + ], + [ + [310, 19, 41, 6, -20, -52] + ], + [ + [352, 19, 35, 12, -17, -55] + ], + [ + [388, 19, 24, 16, -12, -57] + ], + [ + [413, 19, 10, 17, -5, -57] + ] + ], +} + +export const LIGHTNINGJAVELIN_META: MissileMeta = { + name: "lightningjavelin", + celFile: "LightningJavelin", + width: 1024, + height: 642, + directions: 16, + framesPerDirection: 5, + animSpeed: 16, + groups: [ + [ + [0, 0, 100, 63, -42, -83], + [101, 0, 100, 63, -42, -83], + [202, 0, 100, 63, -42, -83], + [303, 0, 100, 63, -42, -83], + [404, 0, 100, 63, -42, -83] + ], + [ + [505, 0, 111, 67, -39, -89], + [617, 0, 111, 67, -39, -89], + [729, 0, 111, 67, -39, -89], + [841, 0, 111, 67, -39, -89], + [0, 68, 111, 67, -39, -89] + ], + [ + [112, 68, 108, 67, -68, -89], + [221, 68, 108, 67, -68, -89], + [330, 68, 108, 67, -68, -89], + [439, 68, 108, 67, -68, -89], + [548, 68, 108, 67, -68, -89] + ], + [ + [657, 68, 101, 62, -60, -82], + [759, 68, 101, 62, -60, -82], + [861, 68, 101, 62, -60, -82], + [0, 136, 101, 62, -60, -82], + [102, 136, 101, 62, -60, -82] + ], + [ + [204, 136, 60, 71, -31, -89], + [265, 136, 60, 71, -31, -89], + [326, 136, 60, 71, -31, -89], + [387, 136, 60, 71, -31, -89], + [448, 136, 60, 71, -31, -89] + ], + [ + [509, 136, 133, 60, -45, -86], + [643, 136, 133, 60, -45, -86], + [777, 136, 133, 60, -45, -86], + [0, 208, 133, 60, -45, -86], + [134, 208, 133, 60, -45, -86] + ], + [ + [268, 208, 56, 79, -27, -90], + [325, 208, 56, 79, -27, -90], + [382, 208, 56, 79, -27, -90], + [439, 208, 56, 79, -27, -90], + [496, 208, 56, 79, -27, -90] + ], + [ + [553, 208, 131, 60, -86, -85], + [685, 208, 131, 60, -86, -85], + [817, 208, 131, 60, -86, -85], + [0, 288, 131, 60, -86, -85], + [132, 288, 131, 60, -86, -85] + ], + [ + [264, 288, 71, 69, -37, -88], + [336, 288, 71, 69, -37, -88], + [408, 288, 71, 69, -37, -88], + [480, 288, 71, 69, -37, -88], + [552, 288, 71, 69, -37, -88] + ], + [ + [624, 288, 123, 61, -45, -84], + [748, 288, 123, 61, -45, -84], + [872, 288, 123, 61, -45, -84], + [0, 358, 123, 61, -45, -84], + [124, 358, 123, 61, -45, -84] + ], + [ + [248, 358, 129, 60, -43, -88], + [378, 358, 129, 60, -43, -88], + [508, 358, 129, 60, -43, -88], + [638, 358, 129, 60, -43, -88], + [768, 358, 129, 60, -43, -88] + ], + [ + [898, 358, 78, 76, -33, -90], + [0, 435, 78, 76, -33, -90], + [79, 435, 78, 76, -33, -90], + [158, 435, 78, 76, -33, -90], + [237, 435, 78, 76, -33, -90] + ], + [ + [316, 435, 76, 76, -41, -90], + [393, 435, 76, 76, -41, -90], + [470, 435, 76, 76, -41, -90], + [547, 435, 76, 76, -41, -90], + [624, 435, 76, 76, -41, -90] + ], + [ + [701, 435, 127, 59, -84, -87], + [829, 435, 127, 59, -84, -87], + [0, 512, 127, 59, -84, -87], + [128, 512, 127, 59, -84, -87], + [256, 512, 127, 59, -84, -87] + ], + [ + [384, 512, 121, 61, -77, -83], + [506, 512, 121, 61, -77, -83], + [628, 512, 121, 61, -77, -83], + [750, 512, 121, 61, -77, -83], + [872, 512, 121, 61, -77, -83] + ], + [ + [0, 574, 71, 68, -36, -86], + [72, 574, 71, 68, -36, -86], + [144, 574, 71, 68, -36, -86], + [216, 574, 71, 68, -36, -86], + [288, 574, 71, 68, -36, -86] + ] + ], +} + +export const MISSILE_METAS: Readonly> = Object.freeze({ + 'firebolt': FIREBOLT_META, + 'fireball': FIREBALL_META, + 'fireexplode': FIREEXPLODE_META, + 'icebolt': ICEBOLT_META, + 'iceblast': ICEBLAST_META, + 'glacialspike': GLACIALSPIKE_META, + 'iceexplode': ICEEXPLODE_META, + 'freezeexplode': FREEZEEXPLODE_META, + 'chargedbolt': CHARGEDBOLT_META, + 'teeth': TEETH_META, + 'teethexplode': TEETHEXPLODE_META, + 'bonespear': BONESPEAR_META, + 'bonespirit': BONESPIRIT_META, + 'bonespiritexplode': BONESPIRITEXPLODE_META, + 'poisonnova': POISONNOVA_META, + 'holybolt': HOLYBOLT_META, + 'blessedhammer': BLESSEDHAMMER_META, + 'magicarrow': MAGICARROW_META, + 'firearrow': FIREARROW_META, + 'icearrow': ICEARROW_META, + 'arrow': ARROW_META, + 'lightningjavelin': LIGHTNINGJAVELIN_META, +}) diff --git a/src/render/renderer.ts b/src/render/renderer.ts index b16906d..3f07c20 100644 --- a/src/render/renderer.ts +++ b/src/render/renderer.ts @@ -80,6 +80,12 @@ export interface DrawOptions { * - 4: Champion / Elite Blue Tint */ readonly paletteRow?: number + /** Destination width in pixels (defaults to frame.width). */ + readonly width?: number + /** Destination height in pixels (defaults to frame.height). */ + readonly height?: number + /** Blend mode for rendering: 'normal' (alpha blend) or 'additive' (translucent spell glow). */ + readonly blendMode?: 'normal' | 'additive' } /** Configuration options and event callbacks for SpriteRenderer. */ @@ -252,6 +258,8 @@ export class SpriteRenderer { private frameDrawCalls = 0 /** Quads submitted since the last {@link begin}. */ private frameQuads = 0 + /** Current active blend mode ('normal' or 'additive'). */ + private currentBlendMode: 'normal' | 'additive' = 'normal' /** All textures allocated and managed by this renderer. */ private readonly allocatedTextures = new Set() @@ -757,6 +765,10 @@ export class SpriteRenderer { this.batchTextureCount = 0 this.frameDrawCalls = 0 this.frameQuads = 0 + if (this.currentBlendMode !== 'normal') { + this.currentBlendMode = 'normal' + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) + } gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight) gl.clearColor(clear[0], clear[1], clear[2], 1) gl.clear(gl.COLOR_BUFFER_BIT) @@ -772,6 +784,17 @@ export class SpriteRenderer { */ draw(frame: AtlasFrame, x: number, y: number, options: DrawOptions = {}): void { if (this.disposed) return + const blendMode = options.blendMode ?? 'normal' + if (blendMode !== this.currentBlendMode) { + this.flush() + this.currentBlendMode = blendMode + const gl = this.gl + if (blendMode === 'additive') { + gl.blendFunc(gl.SRC_ALPHA, gl.ONE) + } else { + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) + } + } const page = options.atlas ?? this.defaultAtlas const unit = this.unitFor(page) const u0 = frame.x / page.width @@ -781,8 +804,10 @@ export class SpriteRenderer { const tint = options.tint const flipped = options.flipX === true const paletteRow = page.indexed === true ? (options.paletteRow ?? 0) : -1 + const drawW = options.width ?? frame.width + const drawH = options.height ?? frame.height this.quad( - x, y, x + frame.width, y + frame.height, + x, y, x + drawW, y + drawH, flipped ? u1 : u0, v0, flipped ? u0 : u1, v1, tint === undefined ? 1 : tint[0], @@ -805,6 +830,11 @@ export class SpriteRenderer { */ drawSolid(x: number, y: number, width: number, height: number, color: readonly [number, number, number, number]): void { if (this.disposed) return + if (this.currentBlendMode !== 'normal') { + this.flush() + this.currentBlendMode = 'normal' + this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA) + } const unit = this.unitFor(this.whiteAtlas) this.quad(x, y, x + width, y + height, 0.5, 0.5, 0.5, 0.5, color[0], color[1], color[2], color[3], unit, -1) } diff --git a/src/scene/act-scene.ts b/src/scene/act-scene.ts index 05debb0..d99a27f 100644 --- a/src/scene/act-scene.ts +++ b/src/scene/act-scene.ts @@ -45,7 +45,7 @@ import { getEmbeddedDropTables } from '../game/embedded-drop-tables.ts' import { buildNpcDef, hasPackedSprite } from '../game/npc.ts' import { npcDialog } from '../game/quests.ts' import type { NpcDef } from '../game/quests.ts' -import { BATCH1_SKILLS, getBatch1SkillDef, isBatch1Skill, getSkillManaCost, getMissileTxtData } from '../game/skills.ts' +import { BATCH1_SKILLS, getBatch1SkillDef, isBatch1Skill, getSkillManaCost, getMissileTxtData, ISO_GROUND_ASPECT_RATIO } from '../game/skills.ts' import type { Projectile } from '../game/skills.ts' import { findSafeDropPosition, calculateBounceHeight, triggerFlippyBounce, type GroundItemEntity } from '../game/ground-items.ts' import { @@ -53,6 +53,8 @@ import { computeInitialGroundLabelLayouts, resolveLadderCollisions, } from '../ui/ground-labels.ts' +import { BAKED_UI_MANIFEST } from '../ui/baked-ui-meta.ts' +import { resolveItemSpriteRect } from '../ui/inventory.ts' import type { AtlasFrame } from '../render/atlas.ts' import { SpriteRenderer } from '../render/renderer.ts' import type { AtlasHandle } from '../render/renderer.ts' @@ -60,8 +62,7 @@ import { buildBounds, intersects, viewportRect } from '../render/cull.ts' import { RoofFadeController } from '../render/roofs.ts' import { facingToDirection } from '../game/character.ts' import type { LoadedMonsterArt } from '../game/monster-art.ts' -import type { MissileMeta } from '../render/missiles-meta.ts' -import { velocityToDccDirection } from '../render/missiles-meta.ts' +import { velocityToDccDirection, MISSILE_METAS, type MissileMeta, type MissileFrameTuple } from '../render/missiles-meta.ts' import { ActorAnimator, type AnimClipMeta } from '../game/actor-animator.ts' import { resolveMonsterArtSpec } from '../game/monster-mapping.ts' import { ACT_NAMES_ZH, LEVEL_NAMES_ZH, getLevelNames, sceneNameZh, variantLabelZh } from '../game/level-names-zh.ts' @@ -997,8 +998,28 @@ export function getSkillRange( const info = getAttackWeaponInfo(weapon) return info.reach } - if (skillId === 36) { - const missile = getMissileTxtData('firebolt') + const missileSkillMap: Record = { + 36: 'firebolt', + 39: 'icebolt', + 45: 'iceblast', + 55: 'glacialspike', + 38: 'chargedbolt', + 67: 'teeth', + 84: 'bonespear', + 93: 'bonespirit', + 92: 'poisonnova', + 101: 'holybolt', + 112: 'blessedhammer', + 6: 'magicarrow', + 7: 'firearrow', + 11: 'icearrow', + 21: 'icearrow', + 12: 'arrow', + 16: 'firearrow', + 20: 'lightningjavelin', + } + if (skillId in missileSkillMap) { + const missile = getMissileTxtData(missileSkillMap[skillId]!) return missile.distancePx || 1000 } const def = getBatch1SkillDef(skillId) @@ -1010,7 +1031,6 @@ export function getSkillRange( case 40: return 0 case 42: return 160 case 44: return 240 - case 47: return 450 case 54: return 450 case 56: return 450 case 59: return 450 @@ -1029,6 +1049,15 @@ export function getSkillMana(skillId: number, hudManager?: HudManager | null): n return getSkillManaCost(skillId, 1) } switch (skillId) { + case 45: return 6 + case 55: return 10 + case 84: return 7 + case 93: return 12 + case 92: return 20 + case 12: return 4 + case 16: return 5 + case 20: return 8 + case 21: return 4 case 40: return 7 case 42: return 9 case 59: return 27 @@ -1264,38 +1293,208 @@ export function castSkill( let damage = 28 let delay = 0 let skillName = '技能' + let missileType: string | undefined = undefined + let pierce: boolean | undefined = undefined + let aoeRadius: number | undefined = undefined + let statusEffect: 'chill' | 'freeze' | 'poison' | undefined = undefined + let statusDuration: number | undefined = undefined + let homing: boolean | undefined = undefined + let spiral: { originX: number; originY: number; angle: number; radius: number } | undefined = undefined + let jitter: boolean | undefined = undefined + let isUndeadOnly: boolean | undefined = undefined + let multiCount = 1 + let spreadAngle = 0 + let isNova = false - if (skillId === 47) { - speed = 450 - range = 450 - damage = 28 + if (skillId === 36) { + const missile = getMissileTxtData('firebolt') + speed = missile.speedPxPerSec || 500 + range = missile.distancePx || 1000 + damage = 16 delay = 0 + missileType = 'firebolt' + skillName = '火弹' + } else if (skillId === 47) { + const missile = getMissileTxtData('fireball') + speed = missile.speedPxPerSec || 500 + range = missile.distancePx || 1000 + damage = 35 + delay = 0 + aoeRadius = 48 + missileType = 'fireball' skillName = '火球' + } else if (skillId === 39) { + const missile = getMissileTxtData('icebolt') + speed = missile.speedPxPerSec || 300 + range = missile.distancePx || 600 + damage = 14 + delay = 0 + statusEffect = 'chill' + statusDuration = 50 + missileType = 'icebolt' + skillName = '冰弹' + } else if (skillId === 45) { + const missile = getMissileTxtData('iceblast') + speed = missile.speedPxPerSec || 300 + range = missile.distancePx || 600 + damage = 24 + delay = 0 + statusEffect = 'freeze' + statusDuration = 75 + missileType = 'iceblast' + skillName = '冰风暴' + } else if (skillId === 55) { + const missile = getMissileTxtData('glacialspike') + speed = missile.speedPxPerSec || 400 + range = missile.distancePx || 640 + damage = 32 + delay = 0 + aoeRadius = 64 + statusEffect = 'freeze' + statusDuration = 50 + missileType = 'glacialspike' + skillName = '冰尖柱' + } else if (skillId === 38) { + const missile = getMissileTxtData('chargedbolt') + speed = missile.speedPxPerSec || 300 + range = missile.distancePx || 1176 + damage = 12 + delay = 0 + missileType = 'chargedbolt' + jitter = true + multiCount = 4 + spreadAngle = 0.45 + skillName = '充能弹' + } else if (skillId === 67) { + const missile = getMissileTxtData('teeth') + speed = missile.speedPxPerSec || 400 + range = missile.distancePx || 800 + damage = 14 + delay = 0 + missileType = 'teeth' + multiCount = 3 + spreadAngle = 0.40 + skillName = '牙' + } else if (skillId === 84) { + const missile = getMissileTxtData('bonespear') + speed = missile.speedPxPerSec || 600 + range = missile.distancePx || 960 + damage = 30 + delay = 0 + pierce = true + missileType = 'bonespear' + skillName = '骨矛' + } else if (skillId === 93) { + const missile = getMissileTxtData('bonespirit') + speed = missile.speedPxPerSec || 300 + range = missile.distancePx || 1536 + damage = 45 + delay = 0 + homing = true + missileType = 'bonespirit' + skillName = '骨魂' + } else if (skillId === 92) { + const missile = getMissileTxtData('poisonnova') + speed = missile.speedPxPerSec || 300 + range = missile.distancePx || 360 + damage = 18 + delay = 0 + statusEffect = 'poison' + statusDuration = 100 + missileType = 'poisonnova' + isNova = true + multiCount = 32 + skillName = '剧毒新星' + } else if (skillId === 101) { + const missile = getMissileTxtData('holybolt') + speed = missile.speedPxPerSec || 500 + range = missile.distancePx || 1000 + damage = 35 + delay = 0 + isUndeadOnly = true + missileType = 'holybolt' + skillName = '圣光弹' + } else if (skillId === 112) { + const missile = getMissileTxtData('blessedhammer') + speed = missile.speedPxPerSec || 450 + range = missile.distancePx || 2160 + damage = 40 + delay = 0 + pierce = true + missileType = 'blessedhammer' + const baseAngle = Math.atan2((targetY - player.y) / ISO_GROUND_ASPECT_RATIO, targetX - player.x) + spiral = { originX: player.x, originY: player.y, angle: baseAngle, radius: 12 } + skillName = '祝福之槌' + } else if (skillId === 6) { + const missile = getMissileTxtData('magicarrow') + speed = missile.speedPxPerSec || 600 + range = missile.distancePx || 960 + damage = 18 + delay = 0 + missileType = 'magicarrow' + skillName = '魔法箭' + } else if (skillId === 7) { + const missile = getMissileTxtData('firearrow') + speed = missile.speedPxPerSec || 600 + range = missile.distancePx || 960 + damage = 20 + delay = 0 + missileType = 'firearrow' + skillName = '火箭' + } else if (skillId === 11) { + const missile = getMissileTxtData('icearrow') + speed = missile.speedPxPerSec || 600 + range = missile.distancePx || 960 + damage = 22 + delay = 0 + statusEffect = 'chill' + statusDuration = 50 + missileType = 'icearrow' + skillName = '冰箭' + } else if (skillId === 21) { + const missile = getMissileTxtData('icearrow') + speed = missile.speedPxPerSec || 600 + range = missile.distancePx || 960 + damage = 26 + delay = 0 + statusEffect = 'freeze' + statusDuration = 50 + missileType = 'icearrow' + skillName = '急冻箭' + } else if (skillId === 12) { + const missile = getMissileTxtData('arrow') + speed = missile.speedPxPerSec || 600 + range = missile.distancePx || 960 + damage = 16 + delay = 0 + missileType = 'arrow' + multiCount = 5 + spreadAngle = 0.50 + skillName = '多重箭' + } else if (skillId === 16) { + const missile = getMissileTxtData('firearrow') + speed = missile.speedPxPerSec || 600 + range = missile.distancePx || 960 + damage = 25 + delay = 0 + aoeRadius = 48 + missileType = 'firearrow' + skillName = '爆裂箭' + } else if (skillId === 20) { + const missile = getMissileTxtData('lightningjavelin') + speed = missile.speedPxPerSec || 750 + range = missile.distancePx || 750 + damage = 35 + delay = 0 + pierce = true + missileType = 'lightningjavelin' + skillName = '闪电之枪' } else if (skillId === 64) { speed = 400 range = 480 damage = 35 delay = 25 skillName = '冰封球' - } else if (skillId === 36) { - const missile = getMissileTxtData('firebolt') - speed = missile.speedPxPerSec || 500 - range = missile.distancePx || 1000 - damage = 16 - delay = 0 - skillName = '火弹' - } else if (skillId === 39) { - speed = 450 - range = 400 - damage = 14 - delay = 0 - skillName = '冰弹' - } else if (skillId === 38) { - speed = 350 - range = 350 - damage = 12 - delay = 0 - skillName = '充能弹' } else if (skillId === 49) { speed = 600 range = 500 @@ -1319,23 +1518,90 @@ export function castSkill( const dx = targetX - player.x const dy = targetY - player.y - const len = Math.hypot(dx, dy) + const baseAngle = Math.atan2(dy, dx) const perTick = speed / 25 const ttl = Math.max(1, Math.round(range / perTick)) - const projectile: Projectile = { - skillId: String(skillId), - x: player.x, - y: player.y, - vx: len > 0 ? (dx / len) * perTick : perTick, - vy: len > 0 ? (dy / len) * perTick : 0, - damage, - ttl, - fromPlayer: true, - missileType: skillId === 36 ? 'firebolt' : undefined, + if (isNova) { + for (let i = 0; i < multiCount; i++) { + const angle = (i / multiCount) * 2 * Math.PI + const pVx = Math.cos(angle) * perTick + const pVy = Math.sin(angle) * (perTick * ISO_GROUND_ASPECT_RATIO) + engine.projectiles.push({ + skillId: String(skillId), + x: player.x, + y: player.y, + vx: pVx, + vy: pVy, + damage, + ttl, + fromPlayer: true, + missileType, + statusEffect, + statusDuration, + }) + } + } else if (multiCount > 1) { + const startAngle = baseAngle - spreadAngle / 2 + const step = spreadAngle / (multiCount - 1) + for (let i = 0; i < multiCount; i++) { + const angle = startAngle + i * step + const pVx = Math.cos(angle) * perTick + const pVy = Math.sin(angle) * perTick + engine.projectiles.push({ + skillId: String(skillId), + x: player.x, + y: player.y, + vx: pVx, + vy: pVy, + damage, + ttl, + fromPlayer: true, + missileType, + jitter, + pierce, + aoeRadius, + statusEffect, + statusDuration, + isUndeadOnly, + }) + } + } else { + let pVx: number + let pVy: number + let pX = player.x + let pY = player.y + if (spiral !== undefined) { + pX = spiral.originX + Math.cos(spiral.angle) * spiral.radius + pY = spiral.originY + Math.sin(spiral.angle) * (spiral.radius * ISO_GROUND_ASPECT_RATIO) + pVx = -Math.sin(spiral.angle) * 18 + pVy = Math.cos(spiral.angle) * (18 * ISO_GROUND_ASPECT_RATIO) + } else { + const len = Math.hypot(dx, dy) + pVx = len > 0 ? (dx / len) * perTick : perTick + pVy = len > 0 ? (dy / len) * perTick : 0 + } + engine.projectiles.push({ + skillId: String(skillId), + x: pX, + y: pY, + vx: pVx, + vy: pVy, + damage, + ttl, + fromPlayer: true, + missileType, + pierce, + aoeRadius, + statusEffect, + statusDuration, + homing, + spiral, + jitter, + isUndeadOnly, + }) } - engine.projectiles.push(projectile) player.cooldown = delay > 0 ? delay : 10 engine.metrics.casts += 1 status.textContent = `施展技能:${skillName}` @@ -1461,6 +1727,10 @@ export class SceneMouseController { return } this.engine.groundItems.remove(item.id) + const gIdx = this.engine.ground.findIndex(g => Math.hypot(g.x - item.x, g.y - item.y) <= 32 || g.item === item.item) + if (gIdx !== -1) { + this.engine.ground.splice(gIdx, 1) + } this.engine.metrics.pickups += 1 this.hudManager.syncPublishedState() this.status.textContent = `拾起物品:${item.nameZh || item.name}` @@ -3249,7 +3519,7 @@ export async function loadMissileArtMap( ): Promise> { const map = new Map() if (typeof fetch === 'undefined') return map - const targets = ['firebolt', 'fireball', 'fireexplode'] + const targets = Object.keys(MISSILE_METAS) const baseCandidates = [ '/missiles', packBase ? `${packBase}/missiles` : '', @@ -3274,8 +3544,8 @@ export async function loadMissileArtMap( } finally { bitmap.close() } - const frames: AtlasFrame[][] = meta.groups.map(group => - group.map(([x, y, width, height, anchorX, anchorY]) => ({ + const frames: AtlasFrame[][] = meta.groups.map((group: readonly MissileFrameTuple[]) => + group.map(([x, y, width, height, anchorX, anchorY]: MissileFrameTuple) => ({ x, y, width, @@ -3297,11 +3567,11 @@ export async function loadMissileArtMap( } /** - * Render a Diablo II 1.13c style Fire Bolt projectile: - * - Uses authentic baked Firebolt.dcc sprite atlas when available. + * Render a Diablo II 1.13c missile projectile: + * - Uses authentic baked DCC sprite atlas when available. * - Gracefully falls back to procedural glowing fireball & trailing particles in test/offline environments. */ -export function drawFireboltProjectile( +export function drawMissileProjectile( renderer: SpriteRenderer, shot: Projectile, missileArt?: LoadedMissileArt, @@ -3309,13 +3579,17 @@ export function drawFireboltProjectile( if (missileArt !== undefined) { const dccDir = velocityToDccDirection(shot.vx, shot.vy, missileArt.meta.directions) const frameCount = Math.max(1, missileArt.meta.framesPerDirection) - const frameIndex = Math.floor(((50 - shot.ttl) * missileArt.meta.animSpeed) / 16) % frameCount + const frameIndex = Math.abs(Math.floor(((100 - shot.ttl) * missileArt.meta.animSpeed) / 16)) % frameCount const group = missileArt.frames[dccDir] ?? missileArt.frames[0] const frame = group?.[frameIndex] ?? group?.[0] if (frame !== undefined) { const drawX = frame.anchorX !== undefined ? shot.x + frame.anchorX : shot.x - frame.width / 2 const drawY = frame.anchorY !== undefined ? shot.y + frame.anchorY : shot.y - frame.height / 2 - renderer.draw(frame, drawX, drawY, { atlas: missileArt.handle }) + const isAdditive = missileArt.meta.name !== 'arrow' + renderer.draw(frame, drawX, drawY, { + atlas: missileArt.handle, + ...(isAdditive ? { blendMode: 'additive' } : {}), + }) return } } @@ -3358,12 +3632,14 @@ export function drawFireboltProjectile( renderer.drawSolid(x - 2, y - 2, 4, 4, [1.0, 1.0, 0.88, 0.98]) } +export const drawFireboltProjectile = drawMissileProjectile + /** - * Render a Diablo II 1.13c style fire explosion (fireexplode): - * - Uses authentic baked FireArrowExplode2.dcc sprite atlas when available. + * Render a Diablo II 1.13c style explosion: + * - Uses authentic baked DCC sprite atlas when available. * - Falls back to procedural explosion in test/offline environments. */ -export function drawFireExplosion( +export function drawExplosion( renderer: SpriteRenderer, exp: ActiveExplosion, explosionArt?: LoadedMissileArt, @@ -3376,7 +3652,10 @@ export function drawFireExplosion( if (frame !== undefined) { const drawX = frame.anchorX !== undefined ? exp.x + frame.anchorX : exp.x - frame.width / 2 const drawY = frame.anchorY !== undefined ? exp.y + frame.anchorY : exp.y - frame.height / 2 - renderer.draw(frame, drawX, drawY, { atlas: explosionArt.handle }) + renderer.draw(frame, drawX, drawY, { + atlas: explosionArt.handle, + blendMode: 'additive', + }) return } } @@ -3414,6 +3693,8 @@ export function drawFireExplosion( } } +export const drawFireExplosion = drawExplosion + /** Quality colors for ground item highlights and glints. */ export const GROUND_ITEM_QUALITY_COLORS: Record = { normal: [0.88, 0.88, 0.88, 1.0], @@ -3428,16 +3709,55 @@ export const GROUND_ITEM_QUALITY_COLORS: Record { + if (globalItemsAtlasHandle !== undefined) return globalItemsAtlasHandle + if (typeof fetch === 'undefined' || typeof createImageBitmap === 'undefined') return undefined + const candidates = [ + '/ui/items-atlas.png', + packBase ? `${packBase}/ui/items-atlas.png` : '', + 'ui/items-atlas.png', + 'public/ui/items-atlas.png', + ].filter(Boolean) + + for (const url of candidates) { + try { + const resp = await fetch(url) + if (!resp.ok) continue + const blob = await resp.blob() + const bitmap = await createImageBitmap(blob) + try { + const handle = renderer.addAtlas(bitmap, BAKED_UI_MANIFEST.atlasWidth, BAKED_UI_MANIFEST.atlasHeight) + globalItemsAtlasHandle = handle + return handle + } finally { + bitmap.close() + } + } catch { + // try next candidate + } + } + return undefined +} + /** * Render a ground item entity with authentic Diablo II 1.13c appearance: * - Parabolic bounce height offset (when dropping or inventory full) - * - Ground item icon / scaled silhouette + * - Authentic item sprite icon / scaled silhouette lying on the ground * - Periodic glint/sparkle 4-point star animation */ export function drawGroundItem( renderer: SpriteRenderer, item: GroundItemEntity, now: number, + itemsAtlas: AtlasHandle | undefined = globalItemsAtlasHandle, ): void { const bounceH = item.bounceState ? calculateBounceHeight(item.bounceState, now) : 0 const baseY = item.y - bounceH @@ -3468,32 +3788,72 @@ export function drawGroundItem( renderer.drawSolid(item.x - w / 2 + 1, baseY - h + 1, w - 2, Math.max(2, Math.floor(h / 3)), [1.0, 0.92, 0.45, 1.0]) } else { // 2. Equipment / Potion / Rune Item Rendering - const w = item.invWidth > 1 ? 22 : 14 - const h = item.invHeight > 2 ? 34 : item.invHeight > 1 ? 24 : 14 + const sr = (itemsAtlas !== undefined && typeof (renderer as any).draw === 'function') + ? resolveItemSpriteRect(item.item || (item as any), BAKED_UI_MANIFEST.itemRects) + : null - // Drop shadow: stays grounded on floor (item.y - 3), alpha fades slightly with height - const shadowAlpha = bounceH > 0 ? Math.max(0.15, 0.38 * (1 - bounceH / 45)) : 0.38 - renderer.drawSolid(item.x - w / 2 - 2, item.y - 3, w + 4, 5, [0, 0, 0, shadowAlpha]) + if (sr !== null && itemsAtlas !== undefined) { + // Authentic Diablo II ground item sprite icon: + // Scales sprite to lie on ground naturally (~16-34px) + const maxDim = Math.max(sr.w, sr.h) + const scale = Math.min(0.75, 34 / maxDim) + const baseW = Math.max(12, Math.round(sr.w * scale)) + const baseH = Math.max(12, Math.round(sr.h * scale)) - // Authentic flippy tumble width modulation during vertical bounce - let renderW = w - if (bounceH > 0 && item.bounceState) { - const elapsed = now - item.bounceState.startTime - // Spin oscillation creating flipping card / tumbling item illusion - const spinScale = Math.abs(Math.cos(elapsed * 0.018)) - renderW = Math.max(6, Math.round(w * (0.4 + 0.6 * spinScale))) + // Drop shadow: stays grounded on floor (item.y - 2), alpha fades slightly with height + const shadowAlpha = bounceH > 0 ? Math.max(0.12, 0.42 * (1 - bounceH / 45)) : 0.42 + const shadowW = Math.max(14, baseW + 6) + renderer.drawSolid(item.x - shadowW / 2, item.y - 2, shadowW, 4, [0, 0, 0, shadowAlpha]) + + // Authentic flippy tumble width modulation during vertical bounce + let renderW = baseW + if (bounceH > 0 && item.bounceState) { + const elapsed = now - item.bounceState.startTime + // Spin oscillation creating flipping card / tumbling item illusion + const spinScale = Math.abs(Math.cos(elapsed * 0.018)) + renderW = Math.max(4, Math.round(baseW * (0.35 + 0.65 * spinScale))) + } + + const frame: AtlasFrame = { + x: sr.x, + y: sr.y, + width: sr.w, + height: sr.h, + } + renderer.draw(frame, item.x - renderW / 2, baseY - baseH, { + atlas: itemsAtlas, + width: renderW, + height: baseH, + }) + } else { + // Fallback for mock renderer or headless unit tests + const w = item.invWidth > 1 ? 22 : 14 + const h = item.invHeight > 2 ? 34 : item.invHeight > 1 ? 24 : 14 + + // Drop shadow: stays grounded on floor (item.y - 3), alpha fades slightly with height + const shadowAlpha = bounceH > 0 ? Math.max(0.15, 0.38 * (1 - bounceH / 45)) : 0.38 + renderer.drawSolid(item.x - w / 2 - 2, item.y - 3, w + 4, 5, [0, 0, 0, shadowAlpha]) + + // Authentic flippy tumble width modulation during vertical bounce + let renderW = w + if (bounceH > 0 && item.bounceState) { + const elapsed = now - item.bounceState.startTime + // Spin oscillation creating flipping card / tumbling item illusion + const spinScale = Math.abs(Math.cos(elapsed * 0.018)) + renderW = Math.max(6, Math.round(w * (0.4 + 0.6 * spinScale))) + } + + // Body + const qr = qColor[0] + const qg = qColor[1] + const qb = qColor[2] + renderer.drawSolid(item.x - renderW / 2, baseY - h, renderW, h, [qr * 0.45, qg * 0.45, qb * 0.45, 0.9]) + // Border rim + renderer.drawSolid(item.x - renderW / 2, baseY - h, renderW, 2, [qr, qg, qb, 0.95]) + renderer.drawSolid(item.x - renderW / 2, baseY - 2, renderW, 2, [qr, qg, qb, 0.95]) + renderer.drawSolid(item.x - renderW / 2, baseY - h, 2, h, [qr, qg, qb, 0.95]) + renderer.drawSolid(item.x + renderW / 2 - 2, baseY - h, 2, h, [qr, qg, qb, 0.95]) } - - // Body - const qr = qColor[0] - const qg = qColor[1] - const qb = qColor[2] - renderer.drawSolid(item.x - renderW / 2, baseY - h, renderW, h, [qr * 0.45, qg * 0.45, qb * 0.45, 0.9]) - // Border rim - renderer.drawSolid(item.x - renderW / 2, baseY - h, renderW, 2, [qr, qg, qb, 0.95]) - renderer.drawSolid(item.x - renderW / 2, baseY - 2, renderW, 2, [qr, qg, qb, 0.95]) - renderer.drawSolid(item.x - renderW / 2, baseY - h, 2, h, [qr, qg, qb, 0.95]) - renderer.drawSolid(item.x + renderW / 2 - 2, baseY - h, 2, h, [qr, qg, qb, 0.95]) } // 3. Glint / Sparkle 4-Point Star Animation @@ -3561,6 +3921,10 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st void loadMissileArtMap(renderer, packEntityBase).then(map => { missileArtMap = map }) + let itemsAtlasHandle: AtlasHandle | undefined + void loadItemsAtlas(renderer, packEntityBase).then(handle => { + itemsAtlasHandle = handle + }) let monsterWalkFrame = 0 const playerAnimator = new ActorAnimator() @@ -4612,10 +4976,10 @@ if (typeof window !== 'undefined') { for (const shot of engine.projectiles) { pushEntity(shot.x, shot.y, () => { - if (shot.skillId === '36' || shot.skillId === 'firebolt' || shot.missileType === 'firebolt') { - drawFireboltProjectile(renderer, shot, missileArtMap.get('firebolt')) - } else if (shot.skillId === '47' || shot.skillId === 'fireball' || shot.missileType === 'fireball') { - drawFireboltProjectile(renderer, shot, missileArtMap.get('fireball')) + const mType = shot.missileType ?? (shot.skillId === '36' ? 'firebolt' : shot.skillId === '47' ? 'fireball' : undefined) + const art = mType !== undefined ? missileArtMap.get(mType) : undefined + if (art !== undefined) { + drawMissileProjectile(renderer, shot, art) } else { renderer.drawSolid(shot.x - 4, shot.y - 4, 8, 8, [0.9, 0.9, 0.2, 1]) } @@ -4624,25 +4988,17 @@ if (typeof window !== 'undefined') { for (const exp of engine.explosions) { pushEntity(exp.x, exp.y, () => { - drawFireExplosion(renderer, exp, missileArtMap.get('fireexplode')) + const art = missileArtMap.get(exp.missileType) ?? missileArtMap.get('fireexplode') + drawExplosion(renderer, exp, art) }) } for (const gItem of engine.groundItems.all) { pushEntity(gItem.x, gItem.y, () => { - drawGroundItem(renderer, gItem, renderStarted) + drawGroundItem(renderer, gItem, renderStarted, itemsAtlasHandle) }) } - if (engine.groundItems.count === 0 && engine.ground.length > 0) { - for (const entry of engine.ground) { - pushEntity(entry.x, entry.y, () => { - const size = 6 - renderer.drawSolid(entry.x - size / 2, entry.y - size, size, size, [0.8, 0.8, 0.8, 1]) - }) - } - } - entities.sort((a, b) => a.depth - b.depth) for (const entity of entities) { diff --git a/src/ui/hotkeys.ts b/src/ui/hotkeys.ts index c8bef9e..6a6395e 100644 --- a/src/ui/hotkeys.ts +++ b/src/ui/hotkeys.ts @@ -35,13 +35,13 @@ export interface HotkeySkillEntry { * left/right action buttons or appear in the Speedbar popup. */ export const PASSIVE_SKILL_IDS: ReadonlySet = new Set([ - // Amazon (Tab 1 Passives) + // Amazon (Tab 1 Passives: Critical Strike 9, Dodge 13, Avoid 18, Penetrate 23, Evade 29, Pierce 33) 9, // Critical Strike - 14, // Penetrate - 17, // Dodge - 22, // Avoid - 27, // Evade - 29, // Pierce + 13, // Dodge + 18, // Avoid + 23, // Penetrate + 29, // Evade + 33, // Pierce // Sorceress Passives 37, // Warmth 61, // Fire Mastery @@ -74,6 +74,24 @@ export function isPassiveSkill(skillId: number): boolean { return PASSIVE_SKILL_IDS.has(skillId) } +/** + * Diablo II v1.13c Skills usable on the Left-Click action button (Skills.txt `leftskill = 1`). + */ +export const LEFT_USABLE_SKILL_IDS: ReadonlySet = new Set([ + 0, 2, 6, 7, 10, 11, 12, 14, 15, 16, 19, 20, 21, 22, 24, 25, 26, 27, 30, 31, 34, 35, + 36, 38, 39, 41, 45, 47, 49, 53, 55, 56, 59, 64, + 67, 73, 84, 93, + 96, 97, 101, 106, 107, 111, 112, 116, 121, + 126, 132, 133, 139, 140, 143, 144, 147, 151, 152, + 225, 229, 230, 232, 238, 239, 240, 242, 243, 245, 248, + 251, 254, 255, 256, 257, 259, 260, 265, 266, 269, 270, 274, 275, 280, +]) + +export function isLeftUsableSkill(skillId: number): boolean { + if (isPassiveSkill(skillId)) return false + return LEFT_USABLE_SKILL_IDS.has(skillId) +} + /** * Diablo II v1.13c Paladin Aura Skills (`Skills.txt` `aura = 1`, Tabs 1 & 2). * Paladin Auras are highlighted in yellow on the Speedbar and Quickbar slots, @@ -190,20 +208,39 @@ export const LEFT_SKILL_BOUNDS = { x: 117, y: 551, width: 48, height: 48 } as co export const RIGHT_SKILL_BOUNDS = { x: 635, y: 551, width: 48, height: 48 } as const export const DEFAULT_SORCERESS_SKILLS: readonly HotkeySkillEntry[] = [ + // Universal Skills { skillId: 0, name: 'Attack', nameZh: '普通攻击', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, { skillId: 2, name: 'Throw', nameZh: '投掷', level: 1, manaCost: 0, leftUsable: true, rightUsable: true }, { skillId: 3, name: 'Unsummon', nameZh: '取消召唤', level: 1, manaCost: 0, leftUsable: false, rightUsable: true }, + // Fire Spells (8 active) { skillId: 36, name: 'Fire Bolt', nameZh: '火弹', level: 5, manaCost: 2.5, leftUsable: true, rightUsable: true }, + { skillId: 41, name: 'Inferno', nameZh: '地狱之火', level: 1, manaCost: 0.6, leftUsable: true, rightUsable: true }, + { skillId: 46, name: 'Blaze', nameZh: '炽烈之径', level: 1, manaCost: 11, leftUsable: false, rightUsable: true }, { skillId: 47, name: 'Fire Ball', nameZh: '火球', level: 8, manaCost: 8.5, leftUsable: true, rightUsable: true }, + { skillId: 51, name: 'Fire Wall', nameZh: '火墙', level: 1, manaCost: 22, leftUsable: false, rightUsable: true }, + { skillId: 52, name: 'Enchant', nameZh: '强化', level: 1, manaCost: 25, leftUsable: false, rightUsable: true }, { skillId: 56, name: 'Meteor', nameZh: '陨石', level: 6, manaCost: 22, leftUsable: true, rightUsable: true }, + { skillId: 62, name: 'Hydra', nameZh: '九头海蛇', level: 1, manaCost: 20, leftUsable: false, rightUsable: true }, + // Lightning Spells (9 active) { skillId: 38, name: 'Charged Bolt', nameZh: '充能弹', level: 4, manaCost: 4, leftUsable: true, rightUsable: true }, - { skillId: 49, name: 'Lightning', nameZh: '闪电', level: 7, manaCost: 11, leftUsable: true, rightUsable: true }, - { skillId: 54, name: 'Teleport', nameZh: '传送', level: 4, manaCost: 21, leftUsable: false, rightUsable: true }, - { skillId: 44, name: 'Frost Nova', nameZh: '霜之新星', level: 3, manaCost: 11, leftUsable: false, rightUsable: true }, - { skillId: 59, name: 'Blizzard', nameZh: '暴风雪', level: 10, manaCost: 27, leftUsable: true, rightUsable: true }, - { skillId: 64, name: 'Frozen Orb', nameZh: '冰封球', level: 12, manaCost: 30, leftUsable: true, rightUsable: true }, - { skillId: 40, name: 'Frozen Armor', nameZh: '冰封装甲', level: 3, manaCost: 7, leftUsable: false, rightUsable: true }, { skillId: 42, name: 'Static Field', nameZh: '静态力场', level: 5, manaCost: 9, leftUsable: false, rightUsable: true }, + { skillId: 43, name: 'Telekinesis', nameZh: '心灵传动', level: 1, manaCost: 7, leftUsable: false, rightUsable: true }, + { skillId: 48, name: 'Nova', nameZh: '新星', level: 1, manaCost: 15, leftUsable: false, rightUsable: true }, + { skillId: 49, name: 'Lightning', nameZh: '闪电', level: 7, manaCost: 11, leftUsable: true, rightUsable: true }, + { skillId: 53, name: 'Chain Lightning', nameZh: '连锁闪电', level: 1, manaCost: 9, leftUsable: true, rightUsable: true }, + { skillId: 54, name: 'Teleport', nameZh: '传送', level: 4, manaCost: 21, leftUsable: false, rightUsable: true }, + { skillId: 57, name: 'Thunder Storm', nameZh: '雷云风暴', level: 1, manaCost: 19, leftUsable: false, rightUsable: true }, + { skillId: 58, name: 'Energy Shield', nameZh: '能量护盾', level: 1, manaCost: 5, leftUsable: false, rightUsable: true }, + // Cold Spells (9 active) + { skillId: 39, name: 'Ice Bolt', nameZh: '冰弹', level: 1, manaCost: 3, leftUsable: true, rightUsable: true }, + { skillId: 40, name: 'Frozen Armor', nameZh: '冰封装甲', level: 3, manaCost: 7, leftUsable: false, rightUsable: true }, + { skillId: 44, name: 'Frost Nova', nameZh: '霜之新星', level: 3, manaCost: 11, leftUsable: false, rightUsable: true }, + { skillId: 45, name: 'Ice Blast', nameZh: '冰风暴', level: 5, manaCost: 8, leftUsable: true, rightUsable: true }, + { skillId: 50, name: 'Shiver Armor', nameZh: '碎冰甲', level: 1, manaCost: 11, leftUsable: false, rightUsable: true }, + { skillId: 55, name: 'Glacial Spike', nameZh: '冰尖柱', level: 10, manaCost: 14.5, leftUsable: true, rightUsable: true }, + { skillId: 59, name: 'Blizzard', nameZh: '暴风雪', level: 10, manaCost: 27, leftUsable: true, rightUsable: true }, + { skillId: 60, name: 'Chilling Armor', nameZh: '寒冰装甲', level: 1, manaCost: 17, leftUsable: false, rightUsable: true }, + { skillId: 64, name: 'Frozen Orb', nameZh: '冰封球', level: 12, manaCost: 30, leftUsable: true, rightUsable: true }, ] export class SkillHotkeysHud { @@ -345,6 +382,17 @@ export class SkillHotkeysHud { this.preloadSkillIcons() } + addOrUpdateSkill(entry: HotkeySkillEntry): void { + if (isPassiveSkill(entry.skillId) || entry.isPassive) return + const idx = this.availableSkills.findIndex(s => s.skillId === entry.skillId) + if (idx >= 0) { + this.availableSkills[idx] = entry + } else { + this.availableSkills.push(entry) + } + this.preloadSkillIcons() + } + getHotkeyLabelForSkill(side: 'left' | 'right', skillId: number): string | null { for (const [key, binding] of this.bindings.entries()) { if (binding.side === side && binding.skillId === skillId) return key diff --git a/src/ui/hud-manager.ts b/src/ui/hud-manager.ts index 56a84bb..6b8038f 100644 --- a/src/ui/hud-manager.ts +++ b/src/ui/hud-manager.ts @@ -17,8 +17,10 @@ import { D2FontRenderer } from './font.ts' import { GlobesHud } from './globes.ts' import { BeltHud } from './belt.ts' -import { SkillHotkeysHud } from './hotkeys.ts' +import { SkillHotkeysHud, isPassiveSkill, isAuraSkill, isLeftUsableSkill } from './hotkeys.ts' import { ControlBarHud, type MiniPanelAction } from './control-bar.ts' +import { SKILLS_BY_ID } from '../data/skills-catalog.ts' +import { calculateManaCost } from '../game/skill-calc-engine.ts' import { InventoryPanel, type EquipSlotId, type UiInventoryItem, resolveItemSpriteRect, INV_GRID_ORIGIN } from './inventory.ts' import { CharacterSheetPanel, type BaseStatKey } from './character-sheet.ts' import { SkillTreePanel, SORCERESS_SKILL_TREE } from './skill-tree-panel.ts' @@ -810,7 +812,7 @@ export class HudManager { this.syncPublishedState() return } else if (this.rightPanel === 'skill') { - this.skillTree.handleClick(rightX, pt.y) + this.skillTree.handleClick(rightX, pt.y, (skillId) => this.handleSkillAllocated(skillId)) if (!this.skillTree.visible) this.rightPanel = 'none' this.syncPublishedState() return @@ -819,6 +821,34 @@ export class HudManager { }) } + private handleSkillAllocated(skillId: number): void { + if (isPassiveSkill(skillId)) return + const catalogEntry = SKILLS_BY_ID[skillId] + if (!catalogEntry) return + + const currentHard = this.skillTree.hardPoints.get(skillId) ?? 1 + const mana = calculateManaCost(catalogEntry, currentHard) + const leftUsable = isLeftUsableSkill(skillId) + + this.hotkeys.addOrUpdateSkill({ + skillId, + name: catalogEntry.name, + nameZh: catalogEntry.nameZh, + level: currentHard, + manaCost: mana, + leftUsable, + rightUsable: true, + isAura: isAuraSkill(skillId), + }) + + const profile = this.currentClass ? this.classProfiles.get(this.currentClass) : undefined + if (profile) { + profile.availableSkills = [...this.hotkeys.availableSkills] + profile.hardPoints = new Map(this.skillTree.hardPoints) + profile.unspentSkillPoints = this.skillTree.unspentSkillPoints + } + } + private buildControlBarState() { return { level: this.charSheet.attrs.level, diff --git a/src/ui/inventory.ts b/src/ui/inventory.ts index 023091e..90bc667 100644 --- a/src/ui/inventory.ts +++ b/src/ui/inventory.ts @@ -289,6 +289,35 @@ export function resolveItemSpriteRect( return itemRects['invcrs'] ?? null } + // Tier 4.5: Name and semantic keyword match for common weapons, armors, and potions + const nameStr = ( + (item.name || '') + ' ' + + (item.id || '') + ' ' + + ((item as any).nameZh || '') + ' ' + + ((item as any).base?.name || '') + ' ' + + ((item as any).base?.nameZh || '') + ).toLowerCase() + + if (nameStr.includes('sword') || nameStr.includes('剑')) return itemRects['invssd'] ?? itemRects['invbsd'] ?? itemRects['invcrs'] ?? null + if (nameStr.includes('axe') || nameStr.includes('斧')) return itemRects['invhax'] ?? itemRects['invbax'] ?? null + if (nameStr.includes('bow') || nameStr.includes('弓')) return itemRects['invsbw'] ?? itemRects['invhbw'] ?? null + if (nameStr.includes('shield') || nameStr.includes('盾')) return itemRects['invsml'] ?? itemRects['invlrg'] ?? itemRects['invkit'] ?? null + if (nameStr.includes('helm') || nameStr.includes('cap') || nameStr.includes('盔') || nameStr.includes('帽')) return itemRects['invcap'] ?? itemRects['invhlm'] ?? null + if (nameStr.includes('armor') || nameStr.includes('plate') || nameStr.includes('甲')) return itemRects['invlea'] ?? itemRects['invqui'] ?? itemRects['invfld'] ?? null + if (nameStr.includes('potion') || nameStr.includes('药')) { + if (nameStr.includes('mana') || nameStr.includes('法力') || nameStr.includes('蓝')) return itemRects['invmp1'] ?? itemRects['invhp1'] ?? null + if (nameStr.includes('rejuv') || nameStr.includes('活力') || nameStr.includes('紫')) return itemRects['invrvs'] ?? itemRects['invhp1'] ?? null + return itemRects['invhp1'] ?? null + } + if (nameStr.includes('ring') || nameStr.includes('戒')) return itemRects['invrin1'] ?? null + if (nameStr.includes('amulet') || nameStr.includes('项链')) return itemRects['invamu1'] ?? null + if (nameStr.includes('boot') || nameStr.includes('靴') || nameStr.includes('鞋')) return itemRects['invlbt'] ?? itemRects['invhbt'] ?? null + if (nameStr.includes('glove') || nameStr.includes('手套')) return itemRects['invlgl'] ?? itemRects['invhgl'] ?? null + if (nameStr.includes('belt') || nameStr.includes('腰带') || nameStr.includes('带')) return itemRects['invlbl'] ?? itemRects['invhbl'] ?? null + if (nameStr.includes('rune') || nameStr.includes('符文')) return itemRects['invr01'] ?? null + if (nameStr.includes('scroll') || nameStr.includes('卷轴')) return itemRects['invtsc'] ?? itemRects['invisc'] ?? null + if (nameStr.includes('gold') || nameStr.includes('金币')) return itemRects['invgld'] ?? null + // Tier 5: Dimension-based fallback guarantee (w x h in cells) const w = item.invWidth ?? (item as any).width ?? 1 const h = item.invHeight ?? (item as any).height ?? 1 diff --git a/tests/glacial-spike-quickbar.test.ts b/tests/glacial-spike-quickbar.test.ts new file mode 100644 index 0000000..25f3353 --- /dev/null +++ b/tests/glacial-spike-quickbar.test.ts @@ -0,0 +1,159 @@ +import { describe, it, expect, beforeEach } from 'vitest' +import { SkillHotkeysHud, DEFAULT_SORCERESS_SKILLS, LEFT_SKILL_BOUNDS, RIGHT_SKILL_BOUNDS } from '../src/ui/hotkeys.ts' +import { HudManager } from '../src/ui/hud-manager.ts' +import { CLASS_DEFAULT_SKILLS, createStarterProfileForClass } from '../src/game/class-starter-profiles.ts' +import { SKILLS_BY_ID } from '../src/data/skills-catalog.ts' + +describe('Issue Fix: Glacial Spike (#55) and All Active Skills on Quickbar Speedbars', () => { + let hud: SkillHotkeysHud + + beforeEach(() => { + hud = new SkillHotkeysHud() + }) + + describe('1. Sorceress Right-Click & Left-Click Quickbar includes Glacial Spike', () => { + it('has Glacial Spike (55) in DEFAULT_SORCERESS_SKILLS with level 10 and authentic mana', () => { + const entry = DEFAULT_SORCERESS_SKILLS.find(s => s.skillId === 55) + expect(entry).toBeDefined() + expect(entry!.name).toBe('Glacial Spike') + expect(entry!.nameZh).toBe('冰尖柱') + expect(entry!.level).toBe(10) + expect(entry!.manaCost).toBeCloseTo(14.5, 1) + expect(entry!.leftUsable).toBe(true) + expect(entry!.rightUsable).toBe(true) + }) + + it('shows Glacial Spike in right-click speedbar popup cells', () => { + const rightCells = hud.getSpeedbarSkills('right') + const spikeCell = rightCells.find(c => c.skill.skillId === 55) + expect(spikeCell).toBeDefined() + expect(spikeCell!.skill.name).toBe('Glacial Spike') + expect(spikeCell!.skill.nameZh).toBe('冰尖柱') + }) + + it('shows Glacial Spike in left-click speedbar popup cells', () => { + const leftCells = hud.getSpeedbarSkills('left') + const spikeCell = leftCells.find(c => c.skill.skillId === 55) + expect(spikeCell).toBeDefined() + expect(spikeCell!.skill.name).toBe('Glacial Spike') + }) + + it('assigns Glacial Spike to right-click slot when clicked in right speedbar', () => { + hud.openSpeedbar('right') + expect(hud.selectionOpen).toBe('right') + + const rightCells = hud.getSpeedbarSkills('right') + const spikeCell = rightCells.find(c => c.skill.skillId === 55)! + expect(spikeCell).toBeDefined() + + const handled = hud.handleClick(spikeCell.x + 10, spikeCell.y + 10) + expect(handled).toBe(true) + expect(hud.rightSkillId).toBe(55) + expect(hud.selectionOpen).toBeNull() + }) + + it('assigns Glacial Spike to left-click slot when clicked in left speedbar', () => { + hud.openSpeedbar('left') + expect(hud.selectionOpen).toBe('left') + + const leftCells = hud.getSpeedbarSkills('left') + const spikeCell = leftCells.find(c => c.skill.skillId === 55)! + expect(spikeCell).toBeDefined() + + const handled = hud.handleClick(spikeCell.x + 10, spikeCell.y + 10) + expect(handled).toBe(true) + expect(hud.leftSkillId).toBe(55) + expect(hud.selectionOpen).toBeNull() + }) + }) + + describe('2. All 7 Classes Starter Profiles include all Active Skills', () => { + it('provides all 26 active skills on Sorceress right-click speedbar', () => { + const sorProfile = createStarterProfileForClass('sor') + const rightSkills = sorProfile.availableSkills.filter(s => s.rightUsable) + // 3 universal (Attack 0, Throw 2, Unsummon 3) + 26 Sorceress active = 29 + expect(rightSkills.length).toBe(29) + + // Glacial Spike is explicitly present + expect(rightSkills.some(s => s.skillId === 55)).toBe(true) + }) + + it('provides all active skills for all 7 classes without passives', () => { + const classes = ['ama', 'sor', 'nec', 'pal', 'bar', 'dru', 'ass'] as const + const expectedActiveCounts: Record = { + ama: 27, // 3 universal + 24 active + sor: 29, // 3 universal + 26 active + nec: 30, // 3 universal + 27 active + pal: 33, // 3 universal + 30 active + bar: 23, // 3 universal + 20 active + dru: 32, // 3 universal + 29 active + ass: 31, // 3 universal + 28 active + } + + for (const cls of classes) { + const skills = CLASS_DEFAULT_SKILLS[cls] + expect(skills.length).toBe(expectedActiveCounts[cls]) + // None should be passive + for (const s of skills) { + expect(s.isPassive).toBeFalsy() + } + } + }) + }) + + describe('3. HudManager Skill Tree Allocation dynamically updates Available Skills', () => { + const mockCanvas = { + width: 800, + height: 600, + style: { cursor: '' }, + addEventListener: () => {}, + removeEventListener: () => {}, + getContext: () => null, + } as unknown as HTMLCanvasElement + + function createMockHud() { + const hud = new HudManager(mockCanvas, { + onToggleAutomap: () => {}, + onWaypointTeleport: () => {}, + }) + hud.switchClass('sor') + return hud + } + + it('initializes HudManager with Glacial Spike available in Sorceress profile', () => { + const hudManager = createMockHud() + expect(hudManager.hotkeys.availableSkills.some(s => s.skillId === 55)).toBe(true) + }) + + it('allocates new skill in skill tree and adds it to hotkeys.availableSkills', () => { + const hudManager = createMockHud() + // Open Skill tree panel + hudManager.rightPanel = 'skill' + hudManager.skillTree.visible = true + hudManager.skillTree.unspentSkillPoints = 5 + + // Select lightning tab (tab 1) + hudManager.skillTree.activeTab = 1 + + // Find Nova (48) which requires level 12 and has reqskills: Static Field (42) which is already allocated in starter + const nova = hudManager.hotkeys.availableSkills.find(s => s.skillId === 48) + expect(nova).toBeDefined() + + // Allocate point into Nova by clicking on it + const node = hudManager.skillTree.getSkillTree().find(n => n.skillId === 48)! + expect(node).toBeDefined() + + const prevPoints = hudManager.skillTree.hardPoints.get(48) ?? 0 + const allocated = hudManager.skillTree.allocateSkill(48) + expect(allocated).toBe(true) + + // Test handleSkillAllocated + const privateMethod = (hudManager as any).handleSkillAllocated.bind(hudManager) + privateMethod(48) + + const updatedNova = hudManager.hotkeys.availableSkills.find(s => s.skillId === 48) + expect(updatedNova).toBeDefined() + expect(updatedNova!.level).toBe(prevPoints + 1) + }) + }) +}) diff --git a/tests/ground-items-pickup.test.ts b/tests/ground-items-pickup.test.ts index bc734be..61b00d9 100644 --- a/tests/ground-items-pickup.test.ts +++ b/tests/ground-items-pickup.test.ts @@ -230,5 +230,27 @@ describe('Ground Items Pickup & Pathfinding (Issue #391)', () => { expect(engine.groundItems.count).toBe(0) expect(status.textContent).toBe('拾起物品:戒指') }) + + it('cleans up both groundItems and engine.ground on pickup, leaving zero residual dots', () => { + const engine = createTestEngine() + engine.world.player.x = 500 + engine.world.player.y = 500 + + const entity = engine.dropItem( + { id: 'sword', name: 'Short Sword', nameZh: '短剑', invWidth: 1, invHeight: 2 }, + 505, + 505, + ) + + expect(engine.groundItems.count).toBe(1) + expect(engine.ground.length).toBe(1) + + const { controller } = createMockController(engine) + controller.pickupGroundItem(entity) + + // Verified: Both groundItems and engine.ground are cleanly cleared + expect(engine.groundItems.count).toBe(0) + expect(engine.ground.length).toBe(0) + }) }) }) diff --git a/tests/ground-items-render.test.ts b/tests/ground-items-render.test.ts index 709113c..615d9e0 100644 --- a/tests/ground-items-render.test.ts +++ b/tests/ground-items-render.test.ts @@ -270,4 +270,53 @@ describe('Issue #389 — Ground Item Rendering & Glint Sparkle Ground Truth', () expect(drawnQuads.length).toBe(6) }) }) + + describe('5. Authentic Ground Item Sprite Parity (Anti-Blue-Box & Clean Pickup)', () => { + it('renders authentic item sprite using itemsAtlas instead of solid color box', () => { + const drawnQuads: { x: number; y: number; w: number; h: number; color: readonly [number, number, number, number] }[] = [] + const drawnSprites: { frame: any; x: number; y: number; options: any }[] = [] + const renderer = { + drawSolid(x: number, y: number, w: number, h: number, color: readonly [number, number, number, number]) { + drawnQuads.push({ x, y, w, h, color }) + }, + draw(frame: any, x: number, y: number, options: any) { + drawnSprites.push({ frame, x, y, options }) + }, + } as unknown as SpriteRenderer + + const mockAtlas = { texture: {} as WebGLTexture, width: 1024, height: 1024 } as any + const magicSword: GroundItemEntity = { + id: 'magic_sword', + item: { name: 'Short Sword', code: 'ssd' }, + name: 'Short Sword', + nameZh: '短剑', + quality: 'magic', + isGold: false, + amount: 1, + invWidth: 1, + invHeight: 3, + dropTime: 0, + x: 100, + y: 200, + cellX: 0, + cellY: 0, + sparklePhase: 0, + } + + drawGroundItem(renderer, magicSword, 1000, mockAtlas) + + // Verified: Sprite is drawn using itemsAtlas + expect(drawnSprites.length).toBe(1) + const sprite = drawnSprites[0]! + expect(sprite.options.atlas).toBe(mockAtlas) + expect(sprite.options.width).toBeGreaterThan(0) + expect(sprite.options.height).toBeGreaterThan(0) + // Drop shadow is drawn on ground + expect(drawnQuads.some(q => q.color[3] < 0.5 && q.y >= 198)).toBe(true) + // Crucial: No opaque blue body box drawn in quads + const blueBody = drawnQuads.find(q => q.color[2] > 0.8 && q.w > 10 && q.h > 10) + expect(blueBody).toBeUndefined() + }) + }) }) + diff --git a/tests/hotkeys-parity.test.ts b/tests/hotkeys-parity.test.ts index af6bfd0..90c0255 100644 --- a/tests/hotkeys-parity.test.ts +++ b/tests/hotkeys-parity.test.ts @@ -33,14 +33,20 @@ describe('Diablo II v1.13c Quickbar & Speedbar Authentic Mechanics (Issue #382)' }) describe('1. Passive Skills Filtering (被动技能不进入快捷栏)', () => { - it('identifies all 23 canonical Diablo II 1.13c passive skills', () => { - // Amazon passives + it('identifies all 26 canonical Diablo II 1.13c passive skills', () => { + // Amazon passives (Critical Strike 9, Dodge 13, Avoid 18, Penetrate 23, Evade 29, Pierce 33) expect(isPassiveSkill(9)).toBe(true) // Critical Strike - expect(isPassiveSkill(14)).toBe(true) // Penetrate - expect(isPassiveSkill(17)).toBe(true) // Dodge - expect(isPassiveSkill(22)).toBe(true) // Avoid - expect(isPassiveSkill(27)).toBe(true) // Evade - expect(isPassiveSkill(29)).toBe(true) // Pierce + expect(isPassiveSkill(13)).toBe(true) // Dodge + expect(isPassiveSkill(18)).toBe(true) // Avoid + expect(isPassiveSkill(23)).toBe(true) // Penetrate + expect(isPassiveSkill(29)).toBe(true) // Evade + expect(isPassiveSkill(33)).toBe(true) // Pierce + + // Amazon active skills that must not be marked as passive + expect(isPassiveSkill(14)).toBe(false) // Power Strike + expect(isPassiveSkill(17)).toBe(false) // Slow Missiles + expect(isPassiveSkill(22)).toBe(false) // Guided Arrow + expect(isPassiveSkill(27)).toBe(false) // Immolation Arrow // Sorceress passives expect(isPassiveSkill(37)).toBe(true) // Warmth diff --git a/tests/hotkeys.test.ts b/tests/hotkeys.test.ts index 487cb55..97a82cf 100644 --- a/tests/hotkeys.test.ts +++ b/tests/hotkeys.test.ts @@ -254,4 +254,93 @@ describe('SkillHotkeysHud & Dual Slot Mechanics', () => { hud.assignSkill('right', 3) expect(hud.rightSkillId).toBe(3) }) + + it('includes Glacial Spike (55) in right-click and left-click speedbars and allows assignment (Issue #385)', () => { + // 1. Verify Glacial Spike is in availableSkills + const glacialSpike = hud.availableSkills.find((s) => s.skillId === 55) + expect(glacialSpike).toBeDefined() + expect(glacialSpike!.name).toBe('Glacial Spike') + expect(glacialSpike!.nameZh).toBe('冰尖柱') + expect(glacialSpike!.level).toBe(10) + expect(glacialSpike!.leftUsable).toBe(true) + expect(glacialSpike!.rightUsable).toBe(true) + + // 2. Right speedbar contains Glacial Spike + const rightSpeedbar = hud.getSpeedbarSkills('right') + const rightCell = rightSpeedbar.find((c) => c.skill.skillId === 55) + expect(rightCell).toBeDefined() + + // Click on Glacial Spike in right speedbar + hud.openSpeedbar('right') + const clickedRight = hud.handleClick(rightCell!.x + 10, rightCell!.y + 10) + expect(clickedRight).toBe(true) + expect(hud.rightSkillId).toBe(55) + expect(hud.selectionOpen).toBeNull() + + // 3. Left speedbar contains Glacial Spike + const leftSpeedbar = hud.getSpeedbarSkills('left') + const leftCell = leftSpeedbar.find((c) => c.skill.skillId === 55) + expect(leftCell).toBeDefined() + + // Click on Glacial Spike in left speedbar + hud.openSpeedbar('left') + const clickedLeft = hud.handleClick(leftCell!.x + 10, leftCell!.y + 10) + expect(clickedLeft).toBe(true) + expect(hud.leftSkillId).toBe(55) + expect(hud.selectionOpen).toBeNull() + + // 4. Icon resolution + const icon = resolveSkillIcon(55) + expect(icon.skillId).toBe(55) + expect(icon.iconPath).toBe('/skills/icon_55.png') + }) + + it('includes all 26 active Sorceress skills on right-click speedbar and excludes all 4 passives', () => { + const rightSkills = hud.getSpeedbarSkills('right') + // 3 universal (Attack 0, Throw 2, Unsummon 3) + 26 class active = 29 skills + expect(rightSkills.length).toBe(29) + + // Verify all 26 active Sorceress skills are present + const activeIds = [ + 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 62, 64, + ] + for (const id of activeIds) { + expect(rightSkills.some((c) => c.skill.skillId === id)).toBe(true) + } + + // Verify the 4 passives are NOT present + const passiveIds = [37, 61, 63, 65] + for (const id of passiveIds) { + expect(rightSkills.some((c) => c.skill.skillId === id)).toBe(false) + } + }) + + it('allows adding and updating skills dynamically via addOrUpdateSkill', () => { + // Add custom skill + hud.addOrUpdateSkill({ + skillId: 48, // Nova + name: 'Nova', + nameZh: '新星', + level: 15, + manaCost: 20, + leftUsable: false, + rightUsable: true, + }) + const nova = hud.availableSkills.find((s) => s.skillId === 48) + expect(nova).toBeDefined() + expect(nova!.level).toBe(15) + + // Cannot add passive skill + hud.addOrUpdateSkill({ + skillId: 37, // Warmth + name: 'Warmth', + nameZh: '暖气', + level: 5, + manaCost: 0, + leftUsable: false, + rightUsable: true, + }) + expect(hud.availableSkills.some((s) => s.skillId === 37)).toBe(false) + }) }) diff --git a/tests/missile-skills-113c.test.ts b/tests/missile-skills-113c.test.ts new file mode 100644 index 0000000..d78a498 --- /dev/null +++ b/tests/missile-skills-113c.test.ts @@ -0,0 +1,1029 @@ +/** + * Diablo II: Lord of Destruction v1.13c — Comprehensive Missile Skills Test Suite + * + * Covers all missile skills across the 4 tiers: + * - Tier 1 (1:1 Direct Projectile): Fire Ball, Ice Bolt, Ice Blast, Magic Arrow, Fire Arrow, Cold Arrow, Ice Arrow + * - Tier 2 (Multi-Projectile Fan / Ring): Teeth, Multiple Shot, Poison Nova + * - Tier 3 (Kinematics: Pierce, Homing, Spiral, Jitter): Bone Spear, Blessed Hammer, Bone Spirit, Charged Bolt + * - Tier 4 (AoE Splash & Entity Filters): Glacial Spike, Exploding Arrow, Holy Bolt + * - Asset & WebGL Rendering: 22 baked DCC missile & explosion atlases, 32-dir DCC lookup, anchor offset rendering + */ +import { describe, expect, it } from 'vitest' +import fs from 'node:fs' +import path from 'node:path' +import { inflateSync } from 'node:zlib' +import { + parseMissilesTxt, + getMissileTxtData, + CANONICAL_113C_MISSILES, + tickProjectiles, + type Projectile, +} from '../src/game/skills.ts' +import { + getSkillRange, + getSkillMana, + castSkill, + drawMissileProjectile, + drawExplosion, + type LoadedMissileArt, +} from '../src/scene/act-scene.ts' +import { GameEngine } from '../src/game/engine.ts' +import { DEMO_EXPERIENCE, DEMO_SKILLS, DEMO_QUESTS } from '../src/game/demo-data.ts' +import { SpriteRenderer, type AtlasHandle } from '../src/render/renderer.ts' +import { MISSILE_METAS, velocityToDccDirection } from '../src/render/missiles-meta.ts' + +const DUMMY_INPUT = { + movement: { x: 0, y: 0 }, + attacking: false, + pickingUp: false, + talking: false, + digits: [], + saving: false, + loading: false, +} + +function createTestEngine(monsters?: { x: number; y: number; hp?: number; isUndead?: boolean; name?: string }[]) { + const engine = new GameEngine( + { + widthPx: 1000, + heightPx: 1000, + overlap: () => 0, + }, + { + spawn: { x: 100, y: 100 }, + stats: [], + xpTable: DEMO_EXPERIENCE, + skills: DEMO_SKILLS, + npcDefs: [], + questDefs: DEMO_QUESTS, + combatOptions: { + playerSpeed: 4, + playerReach: 50, + playerCooldownTicks: 10, + playerDamage: 5, + playerManaPerAttack: 1, + respawnTicks: 100, + }, + talkRadius: 50, + pickupRadius: 30, + inventoryCols: 10, + inventoryRows: 4, + monsterCount: 0, + }, + ) + + if (monsters) { + engine.world.monsters.length = 0 + for (let i = 0; i < monsters.length; i++) { + const m = monsters[i]! + const isUndead = m.isUndead ?? false + engine.world.monsters.push({ + index: i, + stats: { + id: isUndead ? 'skeleton' : 'fallen', + name: m.name ?? (isUndead ? 'Skeleton' : 'Fallen'), + hp: m.hp ?? 100, + damage: 5, + cooldownTicks: 25, + reach: 25, + aggroRadius: 200, + speed: 100, + xp: 10, + }, + x: m.x, + y: m.y, + hp: m.hp ?? 100, + cooldown: 0, + state: 'idle', + facing: 0, + hitFlash: 0, + corpseTicks: 0, + ...(isUndead ? { isUndead: true } : {}), + }) + } + } + + return engine +} + +describe('Diablo II 1.13c Missile Skills Suite', () => { + const missilesTxtPath = path.resolve(__dirname, '../samples/fixtures/data/global/excel/Missiles.txt') + const missilesTxtContent = fs.readFileSync(missilesTxtPath, 'latin1') + const parsedMissiles = parseMissilesTxt(missilesTxtContent) + + // ------------------------------------------------------------- + // TIER 1: Direct 1:1 Projectiles + // ------------------------------------------------------------- + describe('Tier 1: Direct 1:1 Projectiles', () => { + it('Fire Ball (47): authentic physics, fireball missileType, 48px AoE splash', () => { + const fbData = getMissileTxtData('fireball', parsedMissiles) + expect(fbData.vel).toBe(20) + expect(fbData.range).toBe(50) + expect(fbData.speedPxPerSec).toBe(500) + expect(fbData.distancePx).toBe(1000) + expect(fbData.explosionMissile).toMatch(/fireexplode|explodingarrowexp/) + + const engine = createTestEngine([ + { x: 150, y: 100, hp: 100 }, // direct target + { x: 170, y: 100, hp: 100 }, // splash target within 48px + { x: 300, y: 100, hp: 100 }, // out of splash radius + ]) + + const status = { textContent: '' } as HTMLElement + castSkill(47, 200, 100, { + engine, + runtime: {} as any, + hudManager: null, + status, + }) + + expect(engine.projectiles.length).toBe(1) + const proj = engine.projectiles[0]! + expect(proj.missileType).toBe('fireball') + expect(proj.aoeRadius).toBe(48) + expect(proj.damage).toBe(35) + + // Advance until impact + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + // Direct target hit, splash target also damaged, distant target untouched + expect(engine.world.monsters[0]!.hp).toBeLessThan(100) + expect(engine.world.monsters[1]!.hp).toBeLessThan(100) + expect(engine.world.monsters[2]!.hp).toBe(100) + + // Active explosion spawned with fireexplode or explodingarrowexp + expect(engine.explosions.length).toBeGreaterThan(0) + expect(['fireexplode', 'explodingarrowexp']).toContain(engine.explosions[0]!.missileType) + }) + + it('Ice Bolt (39): chill status slows monster speed by 50%', () => { + const engine = createTestEngine([{ x: 140, y: 100, hp: 100 }]) + const status = { textContent: '' } as HTMLElement + castSkill(39, 200, 100, { + engine, + runtime: {} as any, + hudManager: null, + status, + }) + + const proj = engine.projectiles[0]! + expect(proj.missileType).toBe('icebolt') + expect(proj.statusEffect).toBe('chill') + + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + const target = engine.world.monsters[0]! + expect(target.chillTicks).toBeGreaterThan(0) + }) + + it('Ice Blast (45): freeze status incapacitates monster to idle', () => { + const engine = createTestEngine([{ x: 140, y: 100, hp: 100 }]) + const status = { textContent: '' } as HTMLElement + castSkill(45, 200, 100, { + engine, + runtime: {} as any, + hudManager: null, + status, + }) + + const proj = engine.projectiles[0]! + expect(proj.missileType).toBe('iceblast') + expect(proj.statusEffect).toBe('freeze') + + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + const target = engine.world.monsters[0]! + expect(target.frozenTicks).toBeGreaterThan(0) + expect(target.state).toBe('idle') + }) + + it('Amazon Elemental Arrows: Magic Arrow, Fire Arrow, Cold Arrow, Ice Arrow', () => { + const engine = createTestEngine() + const status = { textContent: '' } as HTMLElement + + // Magic Arrow (6) + castSkill(6, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + expect(engine.projectiles[0]!.missileType).toBe('magicarrow') + engine.projectiles.length = 0 + engine.world.player.cooldown = 0 + + // Fire Arrow (7) + castSkill(7, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + expect(engine.projectiles[0]!.missileType).toBe('firearrow') + engine.projectiles.length = 0 + engine.world.player.cooldown = 0 + + // Cold Arrow (11) + castSkill(11, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + expect(engine.projectiles[0]!.missileType).toBe('icearrow') + expect(engine.projectiles[0]!.statusEffect).toBe('chill') + engine.projectiles.length = 0 + engine.world.player.cooldown = 0 + + // Ice Arrow (21) + castSkill(21, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + expect(engine.projectiles[0]!.missileType).toBe('icearrow') + expect(engine.projectiles[0]!.statusEffect).toBe('freeze') + engine.projectiles.length = 0 + }) + }) + + // ------------------------------------------------------------- + // TIER 2: Multi-Projectile Spread (Fan & 360 Nova) + // ------------------------------------------------------------- + describe('Tier 2: Multi-Projectile Spread', () => { + it('Teeth (67): spawns 3 teeth missiles across fan arc', () => { + const engine = createTestEngine() + const status = { textContent: '' } as HTMLElement + castSkill(67, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + + expect(engine.projectiles.length).toBe(3) + for (const p of engine.projectiles) { + expect(p.missileType).toBe('teeth') + } + // Check angles diverge + const angles = engine.projectiles.map(p => Math.atan2(p.vy, p.vx)) + expect(angles[0]).toBeLessThan(angles[1]!) + expect(angles[1]).toBeLessThan(angles[2]!) + }) + + it('Multiple Shot (12): spawns 5 arrows in fan spread', () => { + const engine = createTestEngine() + const status = { textContent: '' } as HTMLElement + castSkill(12, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + + expect(engine.projectiles.length).toBe(5) + for (const p of engine.projectiles) { + expect(p.missileType).toBe('arrow') + } + }) + + it('Poison Nova (92): spawns 32 missiles in 360-degree ring with poison status', () => { + const engine = createTestEngine([{ x: 100, y: 150, hp: 100 }]) + const status = { textContent: '' } as HTMLElement + castSkill(92, 100, 100, { engine, runtime: {} as any, hudManager: null, status }) + + expect(engine.projectiles.length).toBe(32) + for (const p of engine.projectiles) { + expect(p.missileType).toBe('poisonnova') + expect(p.statusEffect).toBe('poison') + // In 2:1 isometric projection, vy is scaled by 0.5 compared to vx + const norm = Math.pow(p.vx, 2) + Math.pow(p.vy / 0.5, 2) + expect(Math.sqrt(norm)).toBeCloseTo(Math.hypot(p.vx, p.vy / 0.5), 1) + } + + // Tick until nova strikes target + for (let t = 0; t < 6; t++) { + engine.tick(DUMMY_INPUT) + } + + const target = engine.world.monsters[0]! + expect(target.poisonTicks).toBeGreaterThan(0) + }) + }) + + // ------------------------------------------------------------- + // TIER 3: Kinematic Variations (Pierce, Spiral, Homing, Jitter) + // ------------------------------------------------------------- + describe('Tier 3: Kinematic Variations', () => { + it('Bone Spear (84): pierces through multiple aligned monsters', () => { + const engine = createTestEngine([ + { x: 140, y: 100, hp: 100 }, + { x: 180, y: 100, hp: 100 }, + { x: 220, y: 100, hp: 100 }, + ]) + const status = { textContent: '' } as HTMLElement + castSkill(84, 300, 100, { engine, runtime: {} as any, hudManager: null, status }) + + expect(engine.projectiles[0]!.pierce).toBe(true) + + // Advance through all 3 monsters + for (let t = 0; t < 10; t++) { + engine.tick(DUMMY_INPUT) + } + + expect(engine.world.monsters[0]!.hp).toBeLessThan(100) + expect(engine.world.monsters[1]!.hp).toBeLessThan(100) + expect(engine.world.monsters[2]!.hp).toBeLessThan(100) + }) + + it('Blessed Hammer (112): moves along Archimedean spiral trajectory on 2:1 isometric ground plane', () => { + const engine = createTestEngine() + const status = { textContent: '' } as HTMLElement + castSkill(112, 100, 200, { engine, runtime: {} as any, hudManager: null, status }) + + const hammer = engine.projectiles[0]! + expect(hammer.missileType).toBe('blessedhammer') + expect(hammer.spiral).toBeDefined() + expect(hammer.pierce).toBe(true) + + const startDist = Math.hypot(hammer.x - hammer.spiral!.originX, (hammer.y - hammer.spiral!.originY) / 0.5) + + // Tick 5 times + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + const currentHammer = engine.projectiles[0]! + expect(currentHammer).toBeDefined() + const currentDist = Math.hypot(currentHammer.x - currentHammer.spiral!.originX, (currentHammer.y - currentHammer.spiral!.originY) / 0.5) + + // Archimedean spiral radius expands outward over time + expect(currentDist).toBeGreaterThan(startDist) + + // Verify that coordinates lie on the 2:1 isometric ground ellipse + const radX = currentHammer.spiral!.radius + const radY = radX * 0.5 + const ellipseRatio = Math.pow((currentHammer.x - currentHammer.spiral!.originX) / radX, 2) + + Math.pow((currentHammer.y - currentHammer.spiral!.originY) / radY, 2) + expect(ellipseRatio).toBeCloseTo(1.0, 1) + }) + + it('Bone Spirit (93): homes in on nearest living enemy', () => { + const engine = createTestEngine([{ x: 200, y: 160, hp: 100 }]) + const status = { textContent: '' } as HTMLElement + + // Cast towards (200, 100), but target is at (200, 160) + castSkill(93, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + + const spirit = engine.projectiles[0]! + expect(spirit.missileType).toBe('bonespirit') + expect(spirit.homing).toBe(true) + + // Track trajectory turning towards monster at y = 160 + for (let t = 0; t < 6; t++) { + engine.tick(DUMMY_INPUT) + } + + const currentSpirit = engine.projectiles[0] + // vy should turn positive towards y = 160 + if (currentSpirit) { + expect(currentSpirit.vy).toBeGreaterThan(0) + } + }) + + it('Charged Bolt (38): wobbles with perpendicular sinusoidal jitter', () => { + const engine = createTestEngine() + const status = { textContent: '' } as HTMLElement + castSkill(38, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + + expect(engine.projectiles.length).toBe(4) + for (const bolt of engine.projectiles) { + expect(bolt.missileType).toBe('chargedbolt') + expect(bolt.jitter).toBe(true) + } + }) + }) + + // ------------------------------------------------------------- + // TIER 4: AoE Splash & Entity Filters + // ------------------------------------------------------------- + describe('Tier 4: AoE Splash & Entity Filters', () => { + it('Glacial Spike (55): AoE 64px freeze and damage on all monsters in radius', () => { + const engine = createTestEngine([ + { x: 150, y: 100, hp: 100 }, // direct + { x: 175, y: 110, hp: 100 }, // within 64px + { x: 300, y: 200, hp: 100 }, // outside + ]) + const status = { textContent: '' } as HTMLElement + castSkill(55, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + expect(engine.world.monsters[0]!.frozenTicks).toBeGreaterThan(0) + expect(engine.world.monsters[1]!.frozenTicks).toBeGreaterThan(0) + expect(engine.world.monsters[2]!.frozenTicks).toBeUndefined() + }) + + it('Holy Bolt (101): only damages Undead monsters', () => { + const engine = createTestEngine([ + { x: 140, y: 100, hp: 100, isUndead: false, name: 'Fallen' }, // Non-undead Demon + ]) + const status = { textContent: '' } as HTMLElement + castSkill(101, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + // Non-undead takes ZERO damage! + expect(engine.world.monsters[0]!.hp).toBe(100) + + // Now with an undead Skeleton + const undeadEngine = createTestEngine([ + { x: 140, y: 100, hp: 100, isUndead: true, name: 'Skeleton' }, + ]) + castSkill(101, 200, 100, { engine: undeadEngine, runtime: {} as any, hudManager: null, status }) + + for (let t = 0; t < 5; t++) { + undeadEngine.tick(DUMMY_INPUT) + } + + // Undead takes full Holy Bolt damage! + expect(undeadEngine.world.monsters[0]!.hp).toBeLessThan(100) + }) + + it('Lightning Bolt (20): piercing lightning javelin', () => { + const engine = createTestEngine([ + { x: 140, y: 100, hp: 100 }, + { x: 180, y: 100, hp: 100 }, + ]) + const status = { textContent: '' } as HTMLElement + castSkill(20, 200, 100, { engine, runtime: {} as any, hudManager: null, status }) + + expect(engine.projectiles[0]!.pierce).toBe(true) + expect(engine.projectiles[0]!.missileType).toBe('lightningjavelin') + + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + expect(engine.world.monsters[0]!.hp).toBeLessThan(100) + expect(engine.world.monsters[1]!.hp).toBeLessThan(100) + }) + }) + + // ------------------------------------------------------------- + // ASSET & WEBGL RENDERING PARITY + // ------------------------------------------------------------- + describe('Missile Assets & WebGL Rendering Parity', () => { + it('Verifies all 22 baked missile metas are exported with authentic DCC properties', () => { + const expectedMetas = [ + 'firebolt', 'fireball', 'fireexplode', + 'icebolt', 'iceblast', 'glacialspike', 'iceexplode', 'freezeexplode', + 'chargedbolt', 'teeth', 'teethexplode', 'bonespear', + 'bonespirit', 'bonespiritexplode', 'poisonnova', + 'holybolt', 'blessedhammer', 'magicarrow', 'firearrow', 'icearrow', 'arrow', 'lightningjavelin' + ] + + for (const name of expectedMetas) { + const meta = MISSILE_METAS[name] + expect(meta, `Meta missing for ${name}`).toBeDefined() + expect(meta.width).toBeGreaterThan(0) + expect(meta.height).toBeGreaterThan(0) + expect(meta.groups.length).toBe(meta.directions) + expect(meta.groups[0]!.length).toBe(meta.framesPerDirection) + } + }) + + it('32-direction DCC lookups resolve accurately for teeth, arrows, poison nova', () => { + // East (vx > 0, vy = 0) + const east32 = velocityToDccDirection(1, 0, 32) + expect(east32).toBeDefined() + + // South (vx = 0, vy > 0) + const south32 = velocityToDccDirection(0, 1, 32) + expect(south32).toBeDefined() + + // North (vx = 0, vy < 0) + const north32 = velocityToDccDirection(0, -1, 32) + expect(north32).toBeDefined() + + // West (vx < 0, vy = 0) + const west32 = velocityToDccDirection(-1, 0, 32) + expect(west32).toBeDefined() + }) + + it('drawMissileProjectile and drawExplosion render with mock WebGL SpriteRenderer', () => { + const draws: { frame: any; x: number; y: number }[] = [] + const fakeRenderer = { + draw: (frame: any, x: number, y: number) => { + draws.push({ frame, x, y }) + }, + drawSolid: () => {}, + } as unknown as SpriteRenderer + + const dummyArt: LoadedMissileArt = { + meta: MISSILE_METAS.bonespear!, + handle: 1 as unknown as AtlasHandle, + frames: [ + [{ x: 0, y: 0, width: 32, height: 32, anchorX: -16, anchorY: -16 }] + ], + } + + const shot: Projectile = { + skillId: '84', + missileType: 'bonespear', + x: 100, + y: 100, + vx: 24, + vy: 0, + damage: 30, + ttl: 40, + fromPlayer: true, + } + + drawMissileProjectile(fakeRenderer, shot, dummyArt) + expect(draws.length).toBe(1) + expect(draws[0]!.x).toBe(100 - 16) // anchor applied! + expect(draws[0]!.y).toBe(100 - 16) + + draws.length = 0 + const expArt: LoadedMissileArt = { + meta: MISSILE_METAS.fireexplode!, + handle: 2 as unknown as AtlasHandle, + frames: [ + [{ x: 0, y: 0, width: 48, height: 48, anchorX: -24, anchorY: -24 }] + ], + } + + drawExplosion(fakeRenderer, { missileType: 'fireexplode', x: 150, y: 150, frame: 0, maxFrames: 12 }, expArt) + expect(draws.length).toBe(1) + expect(draws[0]!.x).toBe(150 - 24) + expect(draws[0]!.y).toBe(150 - 24) + }) + }) + + // ------------------------------------------------------------- + // TIER 5: Isometric Ground Perspective (2:1 Ratio) & Map Coordinates Parity + // ------------------------------------------------------------- + describe('Tier 5: Isometric Ground Perspective (2:1 Ratio) & Map Coordinates Parity', () => { + it('Blessed Hammer spiral trajectory forms an exact 2:1 ellipse on the ground plane across multiple ticks', () => { + const engine = createTestEngine() + const status = { textContent: '' } as HTMLElement + castSkill(112, 100, 200, { engine, runtime: {} as any, hudManager: null, status }) + + const hammer = engine.projectiles[0]! + const originX = hammer.spiral!.originX + const originY = hammer.spiral!.originY + + for (let t = 0; t < 12; t++) { + engine.tick(DUMMY_INPUT) + const cur = engine.projectiles[0]! + expect(cur).toBeDefined() + const rX = cur.spiral!.radius + const rY = rX * 0.5 // 2:1 isometric ground foreshortening + const ellipseNorm = Math.pow((cur.x - originX) / rX, 2) + Math.pow((cur.y - originY) / rY, 2) + expect(ellipseNorm).toBeCloseTo(1.0, 2) + + // Verify tangential velocity also reflects the 2:1 aspect ratio + const speedRatio = Math.abs(cur.vy) / (Math.abs(cur.vx) || 0.001) + // vy is scaled by 0.5 relative to horizontal component + expect(Math.abs(cur.vy)).toBeLessThanOrEqual(18 * 0.5 + 0.01) + } + }) + + it('Poison Nova 32-missile radial ring expands as a 2:1 ground ellipse', () => { + const engine = createTestEngine() + const status = { textContent: '' } as HTMLElement + castSkill(92, 100, 100, { engine, runtime: {} as any, hudManager: null, status }) + + expect(engine.projectiles.length).toBe(32) + for (const p of engine.projectiles) { + // Velocities must lie on the ellipse: (vx / speed)^2 + (vy / (0.5 * speed))^2 == 1 + const speed = Math.hypot(p.vx, p.vy / 0.5) + const vEllipse = Math.pow(p.vx / speed, 2) + Math.pow(p.vy / (speed * 0.5), 2) + expect(vEllipse).toBeCloseTo(1.0, 2) + } + + // Advance 5 ticks + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + for (const p of engine.projectiles) { + const dx = p.x - engine.world.player.x + const dy = p.y - engine.world.player.y + const groundRadius = Math.hypot(dx, dy / 0.5) + const posEllipse = Math.pow(dx / groundRadius, 2) + Math.pow(dy / (groundRadius * 0.5), 2) + expect(posEllipse).toBeCloseTo(1.0, 2) + } + }) + + it('AoE splash damage evaluates ground distance with 2:1 isometric metric (Math.hypot(dx, dy / 0.5) <= aoeRadius)', () => { + // Fireball has aoeRadius = 48 + // Origin at (100, 100) + // Monster A at (140, 100): dx=40, dy=0 -> groundDist = 40 <= 48 (HIT) + // Monster B at (100, 120): dx=0, dy=20 -> groundDist = 20 / 0.5 = 40 <= 48 (HIT) + // Monster C at (100, 130): dx=0, dy=30 -> groundDist = 30 / 0.5 = 60 > 48 (MISS, even though Euclidean dy=30 < 48!) + const engine = createTestEngine([ + { x: 100, y: 100, hp: 100 }, // direct hit target + { x: 140, y: 100, hp: 100 }, // A: horizontal within AoE + { x: 100, y: 120, hp: 100 }, // B: vertical within isometric AoE (dy=20 -> ground 40) + { x: 100, y: 130, hp: 100 }, // C: vertical outside isometric AoE (dy=30 -> ground 60) + ]) + const status = { textContent: '' } as HTMLElement + castSkill(47, 100, 100, { engine, runtime: {} as any, hudManager: null, status }) + + // Advance until fireball hits + for (let t = 0; t < 5; t++) { + engine.tick(DUMMY_INPUT) + } + + const monsters = engine.world.monsters + expect(monsters[0]!.hp).toBeLessThan(100) // direct target damaged + expect(monsters[1]!.hp).toBeLessThan(100) // monster A damaged + expect(monsters[2]!.hp).toBeLessThan(100) // monster B damaged (within 2:1 AoE) + expect(monsters[3]!.hp).toBe(100) // monster C UNTOUCHED (outside 2:1 ground AoE) + }) + + it('Strictly distinguishes map simulation coordinates from rendered sprite icon anchor offsets', () => { + const draws: { frame: any; x: number; y: number }[] = [] + const fakeRenderer = { + draw: (frame: any, x: number, y: number) => { + draws.push({ frame, x, y }) + }, + } as unknown as SpriteRenderer + + const dummyArt: LoadedMissileArt = { + meta: MISSILE_METAS.blessedhammer!, + handle: 1 as unknown as AtlasHandle, + frames: [ + [{ x: 0, y: 0, width: 32, height: 32, anchorX: -16, anchorY: -20 }] + ], + } + + // Map coordinate on the ground plane + const mapX = 250 + const mapY = 180 + + const shot: Projectile = { + skillId: '112', + missileType: 'blessedhammer', + x: mapX, + y: mapY, + vx: 12, + vy: 6, // 2:1 velocity + damage: 40, + ttl: 50, + fromPlayer: true, + } + + drawMissileProjectile(fakeRenderer, shot, dummyArt) + expect(draws.length).toBe(1) + + // The projectile coordinate (map coordinate) is unaltered + expect(shot.x).toBe(mapX) + expect(shot.y).toBe(mapY) + + // The rendered icon is translated by the DCC frame anchor, NOT stretched + expect(draws[0]!.x).toBe(mapX + (-16)) + expect(draws[0]!.y).toBe(mapY + (-20)) + expect(draws[0]!.frame.width).toBe(32) + expect(draws[0]!.frame.height).toBe(32) + }) + }) + + describe('Tier 6: Trans = 1 Missile Transparency & Additive Blending (Zero Black Border) Parity', () => { + function decodeRgbaPng(filePath: string): { width: number; height: number; pixels: Uint8Array } { + const buffer = fs.readFileSync(filePath) + const width = buffer.readUInt32BE(16) + const height = buffer.readUInt32BE(20) + const bitDepth = buffer.readUInt8(24) + const colorType = buffer.readUInt8(25) + + expect(bitDepth).toBe(8) + expect(colorType).toBe(6) // Must be 32-bit RGBA + + let offset = 8 + const idatChunks: Buffer[] = [] + while (offset < buffer.length) { + const len = buffer.readUInt32BE(offset) + const type = buffer.subarray(offset + 4, offset + 8).toString('ascii') + if (type === 'IDAT') { + idatChunks.push(buffer.subarray(offset + 8, offset + 8 + len)) + } + offset += 12 + len + } + const decompressed = inflateSync(Buffer.concat(idatChunks)) + const stride = 4 + const rowBytes = width * stride + const pixels = new Uint8Array(width * height * stride) + + let srcOffset = 0 + let dstOffset = 0 + let prevRow: Uint8Array | null = null + + for (let y = 0; y < height; y++) { + const filterType = decompressed[srcOffset++]! + const currentRow = new Uint8Array(rowBytes) + for (let x = 0; x < rowBytes; x++) { + const byte = decompressed[srcOffset++]! + const left = x >= stride ? currentRow[x - stride]! : 0 + const up = prevRow ? prevRow[x]! : 0 + let val = byte + if (filterType === 0) { + val = byte + } else if (filterType === 1) { + val = (byte + left) & 0xff + } else if (filterType === 2) { + val = (byte + up) & 0xff + } else if (filterType === 3) { + val = (byte + Math.floor((left + up) / 2)) & 0xff + } else if (filterType === 4) { + const upLeft = prevRow && x >= stride ? prevRow[x - stride]! : 0 + const p = left + up - upLeft + const pa = Math.abs(p - left) + const pb = Math.abs(p - up) + const pc = Math.abs(p - upLeft) + let pr = left + if (pb < pa && pb <= pc) pr = up + else if (pc < pa) pr = upLeft + val = (byte + pr) & 0xff + } + currentRow[x] = val + } + pixels.set(currentRow, dstOffset) + dstOffset += rowBytes + prevRow = currentRow + } + + return { width, height, pixels } + } + + it('All baked Trans=1 magical missiles and explosions have colorType=6 and ZERO opaque black pixels', () => { + const magicalMissiles = [ + 'firebolt', + 'fireball', + 'fireexplode', + 'icebolt', + 'iceblast', + 'glacialspike', + 'iceexplode', + 'freezeexplode', + 'chargedbolt', + 'teeth', + 'teethexplode', + 'bonespear', + 'bonespirit', + 'bonespiritexplode', + 'poisonnova', + 'holybolt', + 'blessedhammer', + 'magicarrow', + 'firearrow', + 'icearrow', + 'lightningjavelin', + ] + + for (const name of magicalMissiles) { + const pngPath = path.resolve(__dirname, `../public/missiles/${name}.png`) + expect(fs.existsSync(pngPath), `Missing ${name}.png in public/missiles`).toBe(true) + + const { width, height, pixels } = decodeRgbaPng(pngPath) + expect(width).toBeGreaterThan(0) + expect(height).toBeGreaterThan(0) + + let blackNonTransparentCount = 0 + let visibleCount = 0 + + for (let i = 0; i < pixels.length; i += 4) { + const r = pixels[i]! + const g = pixels[i + 1]! + const b = pixels[i + 2]! + const a = pixels[i + 3]! + + const maxRgb = Math.max(r, g, b) + // Black fringe / dark background (max(r,g,b) <= 4, e.g. palette index 172 (4,4,4) or 0 (0,0,0)) + if (maxRgb <= 4 && a > 0) { + blackNonTransparentCount++ + } + if (a > 0 && maxRgb >= 30) { + visibleCount++ + } + } + + // Strict invariant: 0 opaque black pixels, eliminating any black border or box artifacts + expect(blackNonTransparentCount, `${name}.png contains ${blackNonTransparentCount} opaque black pixels!`).toBe(0) + expect(visibleCount, `${name}.png must contain visible spell pixels`).toBeGreaterThan(0) + } + }) + + it('Physical arrow.png is 32-bit RGBA and retains authentic arrow pixels', () => { + const arrowPngPath = path.resolve(__dirname, '../public/missiles/arrow.png') + expect(fs.existsSync(arrowPngPath)).toBe(true) + const { width, height, pixels } = decodeRgbaPng(arrowPngPath) + expect(width).toBeGreaterThan(0) + expect(height).toBeGreaterThan(0) + + let opaqueCount = 0 + for (let i = 0; i < pixels.length; i += 4) { + const a = pixels[i + 3]! + if (a > 200) opaqueCount++ + } + expect(opaqueCount).toBeGreaterThan(0) + }) + + it('drawMissileProjectile passes blendMode: "additive" for magical missiles and normal for physical arrow', () => { + const drawCalls: any[] = [] + const mockRenderer = { + draw(frame: any, x: number, y: number, options?: any) { + drawCalls.push({ frame, x, y, options }) + }, + } as unknown as SpriteRenderer + + const dummyFrame = [{ x: 0, y: 0, width: 32, height: 32, anchorX: -16, anchorY: -16 }] + + // 1. Magical missile (e.g. firebolt) + const fireboltArt: LoadedMissileArt = { + meta: MISSILE_METAS.firebolt!, + handle: 1 as unknown as AtlasHandle, + frames: [dummyFrame], + } + const fireboltShot: Projectile = { + skillId: '36', + missileType: 'firebolt', + x: 100, + y: 100, + vx: 20, + vy: 0, + damage: 10, + ttl: 50, + fromPlayer: true, + } + drawMissileProjectile(mockRenderer, fireboltShot, fireboltArt) + expect(drawCalls.length).toBe(1) + expect(drawCalls[0]!.options?.blendMode).toBe('additive') + + // 2. Physical arrow (arrow) + drawCalls.length = 0 + const arrowArt: LoadedMissileArt = { + meta: MISSILE_METAS.arrow!, + handle: 2 as unknown as AtlasHandle, + frames: [dummyFrame], + } + const arrowShot: Projectile = { + skillId: 'arrow', + missileType: 'arrow', + x: 100, + y: 100, + vx: 20, + vy: 0, + damage: 10, + ttl: 50, + fromPlayer: true, + } + drawMissileProjectile(mockRenderer, arrowShot, arrowArt) + expect(drawCalls.length).toBe(1) + expect(drawCalls[0]!.options?.blendMode).toBeUndefined() + }) + + it('drawExplosion passes blendMode: "additive" for spell explosions', () => { + const drawCalls: any[] = [] + const mockRenderer = { + draw(frame: any, x: number, y: number, options?: any) { + drawCalls.push({ frame, x, y, options }) + }, + } as unknown as SpriteRenderer + + const dummyFrame = [{ x: 0, y: 0, width: 48, height: 48, anchorX: -24, anchorY: -24 }] + const explodeArt: LoadedMissileArt = { + meta: MISSILE_METAS.fireexplode!, + handle: 3 as unknown as AtlasHandle, + frames: [dummyFrame], + } + + drawExplosion(mockRenderer, { + missileType: 'fireexplode', + x: 150, + y: 150, + frame: 2, + maxFrames: 12, + }, explodeArt) + + expect(drawCalls.length).toBe(1) + expect(drawCalls[0]!.options?.blendMode).toBe('additive') + }) + + it('SpriteRenderer dynamically toggles gl.blendFunc and flushes batches on blendMode transition', () => { + let nextId = 1 + const blendFuncCalls: Array<[number, number]> = [] + const drawElementsCalls: number[] = [] + + const gl: any = { + VERTEX_SHADER: 35633, + FRAGMENT_SHADER: 35632, + COMPILE_STATUS: 35713, + LINK_STATUS: 35714, + MAX_TEXTURE_SIZE: 4096, + MAX_TEXTURE_IMAGE_UNITS: 16, + TEXTURE_2D: 3553, + RGBA: 6408, + UNSIGNED_BYTE: 5121, + UNSIGNED_INT: 5125, + FLOAT: 5126, + ARRAY_BUFFER: 34962, + ELEMENT_ARRAY_BUFFER: 34963, + DYNAMIC_DRAW: 35048, + STATIC_DRAW: 35044, + TRIANGLES: 4, + TEXTURE_MIN_FILTER: 10241, + TEXTURE_MAG_FILTER: 10240, + TEXTURE_WRAP_S: 10242, + TEXTURE_WRAP_T: 10243, + CLAMP_TO_EDGE: 33071, + NEAREST: 9728, + BLEND: 3042, + ONE: 1, + SRC_ALPHA: 770, + ONE_MINUS_SRC_ALPHA: 771, + DEPTH_TEST: 2929, + COLOR_BUFFER_BIT: 16384, + TEXTURE0: 33984, + drawingBufferWidth: 800, + drawingBufferHeight: 600, + isContextLost: () => false, + createProgram: () => ({ id: nextId++ }), + deleteProgram: () => {}, + attachShader: () => {}, + linkProgram: () => {}, + getProgramParameter: () => true, + getProgramInfoLog: () => '', + useProgram: () => {}, + createShader: () => ({ id: nextId++ }), + shaderSource: () => {}, + compileShader: () => {}, + getShaderParameter: () => true, + getShaderInfoLog: () => '', + deleteShader: () => {}, + createVertexArray: () => ({ id: nextId++ }), + bindVertexArray: () => {}, + createBuffer: () => ({ id: nextId++ }), + bindBuffer: () => {}, + bufferData: () => {}, + bufferSubData: () => {}, + getAttribLocation: () => 0, + enableVertexAttribArray: () => {}, + vertexAttribPointer: () => {}, + createTexture: () => ({ id: nextId++ }), + bindTexture: () => {}, + texParameteri: () => {}, + pixelStorei: () => {}, + texImage2D: () => {}, + getParameter: (p: number) => (p === 3379 ? 4096 : p === 34930 ? 16 : 0), + getUniformLocation: () => ({}), + uniform2f: () => {}, + uniform1f: () => {}, + uniform1i: () => {}, + uniform1iv: () => {}, + enable: () => {}, + disable: () => {}, + blendFunc: (s: number, d: number) => { + blendFuncCalls.push([s, d]) + }, + viewport: () => {}, + clearColor: () => {}, + clear: () => {}, + drawElements: (_mode: number, count: number) => { + drawElementsCalls.push(count) + }, + deleteBuffer: () => {}, + deleteVertexArray: () => {}, + deleteTexture: () => {}, + } + const canvas: any = { + getContext: () => gl, + width: 800, + height: 600, + addEventListener: () => {}, + removeEventListener: () => {}, + } + const renderer = new SpriteRenderer(canvas) + + // Start frame + renderer.begin([0, 0], 1) + // gl.blendFunc was set to (SRC_ALPHA, ONE_MINUS_SRC_ALPHA) on initialize + expect(blendFuncCalls.length).toBeGreaterThan(0) + expect(blendFuncCalls[0]).toEqual([gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA]) + + const frame = { x: 0, y: 0, width: 32, height: 32 } + + // 1. Draw normal quad + renderer.draw(frame, 10, 10, { blendMode: 'normal' }) + + // 2. Draw additive quad -> must flush and switch blendFunc to (SRC_ALPHA, ONE) + const prevCalls = blendFuncCalls.length + renderer.draw(frame, 20, 20, { blendMode: 'additive' }) + expect(blendFuncCalls.length).toBe(prevCalls + 1) + expect(blendFuncCalls[blendFuncCalls.length - 1]).toEqual([gl.SRC_ALPHA, gl.ONE]) + expect(drawElementsCalls.length).toBe(1) // Flushed normal batch (6 indices) + + // 3. Draw another additive quad -> should batch together without switching blendFunc + const callsAfterSecondAdditive = blendFuncCalls.length + renderer.draw(frame, 30, 30, { blendMode: 'additive' }) + expect(blendFuncCalls.length).toBe(callsAfterSecondAdditive) + + // 4. Draw normal quad again -> must flush additive batch and switch blendFunc back + renderer.draw(frame, 40, 40, { blendMode: 'normal' }) + expect(blendFuncCalls[blendFuncCalls.length - 1]).toEqual([gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA]) + expect(drawElementsCalls.length).toBe(2) // Flushed additive batch + + // 5. drawSolid ensures normal blend mode + renderer.draw(frame, 50, 50, { blendMode: 'additive' }) + expect(blendFuncCalls[blendFuncCalls.length - 1]).toEqual([gl.SRC_ALPHA, gl.ONE]) + renderer.drawSolid(0, 0, 10, 10, [1, 0, 0, 1]) + expect(blendFuncCalls[blendFuncCalls.length - 1]).toEqual([gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA]) + + renderer.end() + }) + }) +}) +