pi-extensions 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ralph/import-cc-codex.md +31 -0
- package/.ralph/import-cc-codex.state.json +14 -0
- package/.ralph/mario-not-impl.md +69 -0
- package/.ralph/mario-not-impl.state.json +14 -0
- package/.ralph/mario-not-spec.md +163 -0
- package/.ralph/mario-not-spec.state.json +14 -0
- package/LICENSE +21 -0
- package/README.md +65 -0
- package/RELEASING.md +34 -0
- package/agent-guidance/CHANGELOG.md +4 -0
- package/agent-guidance/README.md +102 -0
- package/agent-guidance/agent-guidance.ts +147 -0
- package/agent-guidance/package.json +22 -0
- package/agent-guidance/setup.sh +75 -0
- package/agent-guidance/templates/CLAUDE.md +5 -0
- package/agent-guidance/templates/CODEX.md +92 -0
- package/agent-guidance/templates/GEMINI.md +5 -0
- package/arcade/CHANGELOG.md +4 -0
- package/arcade/README.md +85 -0
- package/arcade/assets/picman.png +0 -0
- package/arcade/assets/ping.png +0 -0
- package/arcade/assets/spice-invaders.png +0 -0
- package/arcade/assets/tetris.png +0 -0
- package/arcade/mario-not/README.md +30 -0
- package/arcade/mario-not/boss.js +103 -0
- package/arcade/mario-not/camera.js +59 -0
- package/arcade/mario-not/collision.js +91 -0
- package/arcade/mario-not/colors.js +36 -0
- package/arcade/mario-not/constants.js +97 -0
- package/arcade/mario-not/core.js +39 -0
- package/arcade/mario-not/death.js +77 -0
- package/arcade/mario-not/effects.js +84 -0
- package/arcade/mario-not/enemies.js +31 -0
- package/arcade/mario-not/engine.js +171 -0
- package/arcade/mario-not/fireballs.js +98 -0
- package/arcade/mario-not/items.js +24 -0
- package/arcade/mario-not/levels.js +403 -0
- package/arcade/mario-not/logic.js +104 -0
- package/arcade/mario-not/mario-not.ts +297 -0
- package/arcade/mario-not/player.js +244 -0
- package/arcade/mario-not/render.js +257 -0
- package/arcade/mario-not/spec.md +548 -0
- package/arcade/mario-not/state.js +246 -0
- package/arcade/mario-not/tests/e2e.test.js +855 -0
- package/arcade/mario-not/tests/engine.test.js +888 -0
- package/arcade/mario-not/tests/fixtures/story0-frame.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story1-camera.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story1-glyphs.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story10-item.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story11-hazards.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story12-used-block.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story13-pipes.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story14-goal.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story15-hud-narrow.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story16-unknown-tile.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story17-mix.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story18-hud-score.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story19-cue.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story2-enemy.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story20-camera-offset.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story21-hud-zero.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story22-big-viewport.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story23-camera-negative.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story24-camera-width.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story25-camera-positive.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story26-hud-lives.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story27-hud-coins.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story28-item-viewport.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story29-enemy-viewport.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story3-hud.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story30-hud-score.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story31-particles-viewport.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story32-paused-frame.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story4-big.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story5-resume-hud.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story6-particles.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story6-paused.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story7-powerup.txt +4 -0
- package/arcade/mario-not/tests/fixtures/story8-hud-time.txt +2 -0
- package/arcade/mario-not/tests/fixtures/story9-hud-level.txt +2 -0
- package/arcade/mario-not/tiles.js +79 -0
- package/arcade/mario-not/tsconfig.json +14 -0
- package/arcade/mario-not/types.js +225 -0
- package/arcade/package.json +26 -0
- package/arcade/picman.ts +328 -0
- package/arcade/ping.ts +594 -0
- package/arcade/spice-invaders.ts +1104 -0
- package/arcade/tetris.ts +662 -0
- package/code-actions/CHANGELOG.md +4 -0
- package/code-actions/README.md +65 -0
- package/code-actions/actions.ts +107 -0
- package/code-actions/index.ts +148 -0
- package/code-actions/package.json +22 -0
- package/code-actions/search.ts +79 -0
- package/code-actions/snippets.ts +179 -0
- package/code-actions/ui.ts +120 -0
- package/files-widget/CHANGELOG.md +90 -0
- package/files-widget/DESIGN.md +452 -0
- package/files-widget/README.md +122 -0
- package/files-widget/TODO.md +141 -0
- package/files-widget/browser.ts +922 -0
- package/files-widget/comment.ts +5 -0
- package/files-widget/constants.ts +18 -0
- package/files-widget/demo.svg +1 -0
- package/files-widget/file-tree.ts +224 -0
- package/files-widget/file-viewer.ts +93 -0
- package/files-widget/git.ts +107 -0
- package/files-widget/index.ts +140 -0
- package/files-widget/input-utils.ts +3 -0
- package/files-widget/package.json +22 -0
- package/files-widget/types.ts +28 -0
- package/files-widget/utils.ts +26 -0
- package/files-widget/viewer.ts +424 -0
- package/import-cc-codex/research/import-chats-from-other-agents.md +135 -0
- package/import-cc-codex/spec.md +79 -0
- package/package.json +29 -0
- package/ralph-wiggum/CHANGELOG.md +7 -0
- package/ralph-wiggum/README.md +96 -0
- package/ralph-wiggum/SKILL.md +73 -0
- package/ralph-wiggum/index.ts +792 -0
- package/ralph-wiggum/package.json +25 -0
- package/raw-paste/CHANGELOG.md +7 -0
- package/raw-paste/README.md +52 -0
- package/raw-paste/index.ts +112 -0
- package/raw-paste/package.json +22 -0
- package/tab-status/CHANGELOG.md +4 -0
- package/tab-status/README.md +61 -0
- package/tab-status/assets/tab-status.png +0 -0
- package/tab-status/package.json +22 -0
- package/tab-status/tab-status.ts +179 -0
- package/usage-extension/CHANGELOG.md +17 -0
- package/usage-extension/README.md +120 -0
- package/usage-extension/index.ts +628 -0
- package/usage-extension/package.json +22 -0
- package/usage-extension/screenshot.png +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { tileGlyph } = require("./tiles.js");
|
|
5
|
+
const { getCameraX } = require("./camera.js");
|
|
6
|
+
const { COLORS: C, colorize } = require("./colors.js");
|
|
7
|
+
|
|
8
|
+
/** @typedef {import("./types").GameState} GameState */
|
|
9
|
+
/** @typedef {import("./types").EnemyState} EnemyState */
|
|
10
|
+
/** @typedef {import("./types").ItemState} ItemState */
|
|
11
|
+
/** @typedef {import("./types").FireballState} FireballState */
|
|
12
|
+
/** @typedef {import("./types").BossState} BossState */
|
|
13
|
+
|
|
14
|
+
// Animation frames for entities
|
|
15
|
+
const PLAYER_FRAMES_SMALL = ["<>", "><"];
|
|
16
|
+
const PLAYER_FRAMES_BIG_HEAD = ["<>", "><"];
|
|
17
|
+
const PLAYER_FRAMES_BIG_BODY = ["[]"];
|
|
18
|
+
const PLAYER_IDLE_SMALL = "<>";
|
|
19
|
+
const PLAYER_IDLE_BIG_HEAD = "<>";
|
|
20
|
+
const PLAYER_IDLE_BIG_BODY = "[]";
|
|
21
|
+
const PLAYER_JUMP_SMALL = "^^";
|
|
22
|
+
const PLAYER_JUMP_BIG_HEAD = "^^";
|
|
23
|
+
const PLAYER_JUMP_BIG_BODY = "[]";
|
|
24
|
+
|
|
25
|
+
const ENEMY_FRAMES = [`${C.brown}@@${C.reset}`, `${C.brown}oo${C.reset}`, `${C.brown}@@${C.reset}`, `${C.brown}OO${C.reset}`];
|
|
26
|
+
const ITEM_GLYPH = `${C.red}%}${C.reset}`; // mushroom
|
|
27
|
+
const PARTICLE_GLYPH = `${C.brightYellow}**${C.reset}`;
|
|
28
|
+
const FIREBALL_FRAMES = [`${C.orange}()${C.reset}`, `${C.brightRed}{}${C.reset}`];
|
|
29
|
+
const BOSS_BODY = [`${C.green}MM${C.reset}`, `${C.green}WW${C.reset}`];
|
|
30
|
+
const BOSS_HEAD = [`${C.green}><${C.reset}`, `${C.green}<>${C.reset}`];
|
|
31
|
+
|
|
32
|
+
/** @param {GameState} state @returns {string} */
|
|
33
|
+
function getPlayerGlyph(state) {
|
|
34
|
+
const player = state.player;
|
|
35
|
+
const tick = state.tick || 0;
|
|
36
|
+
const isMoving = Math.abs(player.vx) > 0.1;
|
|
37
|
+
const inAir = !player.onGround;
|
|
38
|
+
const color = player.size === "big" ? C.brightCyan : C.cyan;
|
|
39
|
+
|
|
40
|
+
// Blink when invulnerable
|
|
41
|
+
if (player.invuln && player.invuln > 0 && Math.floor(tick / 4) % 2 === 0) {
|
|
42
|
+
return " "; // invisible during blink
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (player.size === "big") {
|
|
46
|
+
if (inAir) return colorize(PLAYER_JUMP_BIG_BODY, color);
|
|
47
|
+
if (!isMoving) return colorize(PLAYER_IDLE_BIG_BODY, color);
|
|
48
|
+
const frame = Math.floor(tick / 6) % PLAYER_FRAMES_BIG_BODY.length;
|
|
49
|
+
return colorize(PLAYER_FRAMES_BIG_BODY[frame], color);
|
|
50
|
+
} else {
|
|
51
|
+
if (inAir) return colorize(PLAYER_JUMP_SMALL, color);
|
|
52
|
+
if (!isMoving) return colorize(PLAYER_IDLE_SMALL, color);
|
|
53
|
+
const frame = Math.floor(tick / 6) % PLAYER_FRAMES_SMALL.length;
|
|
54
|
+
return colorize(PLAYER_FRAMES_SMALL[frame], color);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** @param {GameState} state @returns {string} */
|
|
59
|
+
function getPlayerHeadGlyph(state) {
|
|
60
|
+
const player = state.player;
|
|
61
|
+
const tick = state.tick || 0;
|
|
62
|
+
const isMoving = Math.abs(player.vx) > 0.1;
|
|
63
|
+
const inAir = !player.onGround;
|
|
64
|
+
const color = C.brightCyan;
|
|
65
|
+
|
|
66
|
+
// Blink when invulnerable
|
|
67
|
+
if (player.invuln && player.invuln > 0 && Math.floor(tick / 4) % 2 === 0) {
|
|
68
|
+
return " ";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (inAir) return colorize(PLAYER_JUMP_BIG_HEAD, color);
|
|
72
|
+
if (!isMoving) return colorize(PLAYER_IDLE_BIG_HEAD, color);
|
|
73
|
+
const frame = Math.floor(tick / 6) % PLAYER_FRAMES_BIG_HEAD.length;
|
|
74
|
+
return colorize(PLAYER_FRAMES_BIG_HEAD[frame], color);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** @param {EnemyState} enemy @param {number} tick @returns {string} */
|
|
78
|
+
function getEnemyGlyph(enemy, tick) {
|
|
79
|
+
// Animate based on position + tick for variety
|
|
80
|
+
const phase = Math.floor(enemy.x * 3 + tick / 8) % ENEMY_FRAMES.length;
|
|
81
|
+
return ENEMY_FRAMES[phase];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** @param {GameState} state @param {number} viewportWidth @param {number} viewportHeight @returns {string} */
|
|
85
|
+
function renderViewport(state, viewportWidth, viewportHeight) {
|
|
86
|
+
const level = state.level;
|
|
87
|
+
const cameraX = getCameraX(state, viewportWidth);
|
|
88
|
+
const rows = [];
|
|
89
|
+
for (let y = 0; y < viewportHeight; y += 1) {
|
|
90
|
+
const row = [];
|
|
91
|
+
for (let x = 0; x < viewportWidth; x += 1) {
|
|
92
|
+
const worldX = Math.floor(cameraX + x);
|
|
93
|
+
const tile =
|
|
94
|
+
worldX >= 0 && worldX < level.width && y >= 0 && y < level.height
|
|
95
|
+
? level.tiles[y][worldX]
|
|
96
|
+
: " ";
|
|
97
|
+
row.push(tileGlyph(tile));
|
|
98
|
+
}
|
|
99
|
+
rows.push(row);
|
|
100
|
+
}
|
|
101
|
+
renderEnemies(rows, state.enemies, cameraX, state.tick);
|
|
102
|
+
renderItems(rows, state.items, cameraX);
|
|
103
|
+
renderParticles(rows, state.particles, cameraX);
|
|
104
|
+
if (state.fireballs) renderFireballs(rows, state.fireballs, cameraX, state.tick);
|
|
105
|
+
if (state.boss) renderBoss(rows, state.boss, cameraX, state.tick);
|
|
106
|
+
const px = Math.floor(state.player.x - cameraX);
|
|
107
|
+
const py = Math.floor(state.player.y);
|
|
108
|
+
const playerGlyph = getPlayerGlyph(state);
|
|
109
|
+
if (py >= 0 && py < viewportHeight && px >= 0 && px < viewportWidth) {
|
|
110
|
+
rows[py][px] = playerGlyph;
|
|
111
|
+
if (state.player.size === "big" && py - 1 >= 0) {
|
|
112
|
+
rows[py - 1][px] = getPlayerHeadGlyph(state);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const rowStrings = rows.map((row) => row.join(""));
|
|
116
|
+
return applyCue(rowStrings, state.cue).join("\n");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** @param {GameState} state @returns {string} */
|
|
120
|
+
function renderFrame(state) {
|
|
121
|
+
const level = state.level;
|
|
122
|
+
const rows = [];
|
|
123
|
+
for (let y = 0; y < level.height; y += 1) {
|
|
124
|
+
const row = [];
|
|
125
|
+
for (let x = 0; x < level.width; x += 1) {
|
|
126
|
+
const tile = level.tiles[y][x];
|
|
127
|
+
row.push(tileGlyph(tile));
|
|
128
|
+
}
|
|
129
|
+
rows.push(row);
|
|
130
|
+
}
|
|
131
|
+
renderEnemies(rows, state.enemies, 0, state.tick);
|
|
132
|
+
renderItems(rows, state.items, 0);
|
|
133
|
+
renderParticles(rows, state.particles, 0);
|
|
134
|
+
const px = Math.floor(state.player.x);
|
|
135
|
+
const py = Math.floor(state.player.y);
|
|
136
|
+
const playerGlyph = getPlayerGlyph(state);
|
|
137
|
+
if (py >= 0 && py < level.height && px >= 0 && px < level.width) {
|
|
138
|
+
rows[py][px] = playerGlyph;
|
|
139
|
+
if (state.player.size === "big" && py - 1 >= 0) {
|
|
140
|
+
rows[py - 1][px] = getPlayerHeadGlyph(state);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const rowStrings = rows.map((row) => row.join(""));
|
|
144
|
+
return applyCue(rowStrings, state.cue).join("\n");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** @param {GameState} state @param {number} width @returns {string} */
|
|
148
|
+
function renderHud(state, width) {
|
|
149
|
+
const time = Math.max(0, Math.ceil(state.time));
|
|
150
|
+
const levelIndex = state.levelIndex || 1;
|
|
151
|
+
const line1 = fitLine(`NOT MARIO L${levelIndex} TIME ${time}`, width);
|
|
152
|
+
const line2 = fitLine(
|
|
153
|
+
`SCORE ${padNum(state.score, 6)} COIN ${padNum(state.coins, 2)} LIVES ${state.lives}`,
|
|
154
|
+
width
|
|
155
|
+
);
|
|
156
|
+
return `${line1}\n${line2}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Set a glyph at position if within bounds
|
|
161
|
+
* @param {string[][]} rows @param {number} x @param {number} y @param {string} glyph
|
|
162
|
+
*/
|
|
163
|
+
function setGlyph(rows, x, y, glyph) {
|
|
164
|
+
if (y >= 0 && y < rows.length && x >= 0 && x < (rows[0]?.length || 0)) {
|
|
165
|
+
rows[y][x] = glyph;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** @param {string[][]} rows @param {EnemyState[]} enemies @param {number} offsetX @param {number} [tick] */
|
|
170
|
+
function renderEnemies(rows, enemies, offsetX, tick) {
|
|
171
|
+
const t = tick || 0;
|
|
172
|
+
for (const enemy of enemies) {
|
|
173
|
+
if (!enemy.alive) continue;
|
|
174
|
+
setGlyph(rows, Math.floor(enemy.x - offsetX), Math.floor(enemy.y), getEnemyGlyph(enemy, t));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** @param {string[][]} rows @param {ItemState[]} items @param {number} offsetX */
|
|
179
|
+
function renderItems(rows, items, offsetX) {
|
|
180
|
+
for (const item of items) {
|
|
181
|
+
if (!item.alive) continue;
|
|
182
|
+
setGlyph(rows, Math.floor(item.x - offsetX), Math.floor(item.y), ITEM_GLYPH);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** @param {string[][]} rows @param {{ x: number, y: number, life: number }[]} particles @param {number} offsetX */
|
|
187
|
+
function renderParticles(rows, particles, offsetX) {
|
|
188
|
+
for (const p of particles) {
|
|
189
|
+
if (p.life <= 0) continue;
|
|
190
|
+
setGlyph(rows, Math.floor(p.x - offsetX), Math.floor(p.y), PARTICLE_GLYPH);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** @param {string[][]} rows @param {FireballState[]} fireballs @param {number} offsetX @param {number} [tick] */
|
|
195
|
+
function renderFireballs(rows, fireballs, offsetX, tick) {
|
|
196
|
+
const t = tick || 0;
|
|
197
|
+
for (const fb of fireballs) {
|
|
198
|
+
if (!fb.alive) continue;
|
|
199
|
+
const frame = Math.floor(t / 4) % FIREBALL_FRAMES.length;
|
|
200
|
+
setGlyph(rows, Math.floor(fb.x - offsetX), Math.floor(fb.y), FIREBALL_FRAMES[frame]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** @param {string[][]} rows @param {BossState | null} boss @param {number} offsetX @param {number} [tick] */
|
|
205
|
+
function renderBoss(rows, boss, offsetX, tick) {
|
|
206
|
+
if (!boss || !boss.alive) return;
|
|
207
|
+
const t = tick || 0;
|
|
208
|
+
|
|
209
|
+
// Blink when invulnerable
|
|
210
|
+
if (boss.invuln > 0 && Math.floor(t / 4) % 2 === 0) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const bx = Math.floor(boss.x - offsetX);
|
|
215
|
+
const by = Math.floor(boss.y);
|
|
216
|
+
const frame = Math.floor(t / 8) % BOSS_BODY.length;
|
|
217
|
+
|
|
218
|
+
// Render boss (2x2)
|
|
219
|
+
setGlyph(rows, bx, by, BOSS_BODY[frame]);
|
|
220
|
+
setGlyph(rows, bx + 1, by, BOSS_BODY[frame]);
|
|
221
|
+
setGlyph(rows, bx, by - 1, BOSS_HEAD[frame]);
|
|
222
|
+
setGlyph(rows, bx + 1, by - 1, BOSS_HEAD[frame]);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** @param {string[]} rows @param {{ text: string } | null} cue */
|
|
226
|
+
function applyCue(rows, cue) {
|
|
227
|
+
if (!cue || !cue.text) return rows;
|
|
228
|
+
const rowIndex = Math.floor(rows.length / 2);
|
|
229
|
+
const row = rows[rowIndex] || "";
|
|
230
|
+
const start = Math.max(0, Math.floor((row.length - cue.text.length) / 2));
|
|
231
|
+
rows[rowIndex] = row.slice(0, start) + cue.text + row.slice(start + cue.text.length);
|
|
232
|
+
return rows;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** @param {string} line @param {number} width @returns {string} */
|
|
236
|
+
function fitLine(line, width) {
|
|
237
|
+
if (typeof width !== "number") return line;
|
|
238
|
+
if (line.length >= width) return line.slice(0, width);
|
|
239
|
+
return line.padEnd(width, " ");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** @param {number} value @param {number} length @returns {string} */
|
|
243
|
+
function padNum(value, length) {
|
|
244
|
+
return String(value).padStart(length, "0");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
module.exports = {
|
|
248
|
+
ENEMY_FRAMES,
|
|
249
|
+
ITEM_GLYPH,
|
|
250
|
+
PARTICLE_GLYPH,
|
|
251
|
+
getEnemyGlyph,
|
|
252
|
+
getPlayerGlyph,
|
|
253
|
+
getPlayerHeadGlyph,
|
|
254
|
+
renderFrame,
|
|
255
|
+
renderViewport,
|
|
256
|
+
renderHud,
|
|
257
|
+
};
|