Fix/Improve linting

This commit is contained in:
2026-08-06 08:50:21 +02:00
parent f641ad5f43
commit 06a16c5b64
288 changed files with 3372 additions and 1536 deletions
+2
View File
@@ -89,6 +89,8 @@ module.exports = {
] ]
} }
], ],
'curly': ['warn', 'all'],
'brace-style': ['warn', 'stroustrup'],
'eol-last': 'error', 'eol-last': 'error',
'eqeqeq': [ 'eqeqeq': [
'error', 'error',
+5 -3
View File
@@ -1,3 +1,5 @@
/* eslint-disable */
import 'source-map-support/register.js'; import 'source-map-support/register.js';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
@@ -125,7 +127,7 @@ const changelog = cb => {
.map(x => x.replace(/^\[test\]/, '<span class="badge badge-secondary">test</span>')), .map(x => x.replace(/^\[test\]/, '<span class="badge badge-secondary">test</span>')),
})); }));
const type = `{ version: string; changes: string[]; }[]`; const type = `{ version: string; changes: string[]; }[]`;
const code = `/* tslint:disable */\n\nexport const CHANGELOG: ${type} = ${JSON.stringify(object, null, 2)};\n`; const code = `/* eslint:disable */\n\nexport const CHANGELOG: ${type} = ${JSON.stringify(object, null, 2)};\n`;
fs.writeFile('src/ts/generated/changelog.ts', code, 'utf8', cb); fs.writeFile('src/ts/generated/changelog.ts', code, 'utf8', cb);
}; };
@@ -178,7 +180,7 @@ const shaders = cb => {
} }
const dir = path.join('src', 'ts', 'graphics', 'shaders'); const dir = path.join('src', 'ts', 'graphics', 'shaders');
const code = '/* tslint:disable */\n\n' + fs.readdirSync(dir) const code = '/* eslint:disable */\n\n' + fs.readdirSync(dir)
.map(file => [_.camelCase(file.replace(/\.glsl$/, '')), path.join(dir, file)]) .map(file => [_.camelCase(file.replace(/\.glsl$/, '')), path.join(dir, file)])
.map(([name, filePath]) => `export const ${name}Shader = \`${getShaderCode(filePath)}\`;`) .map(([name, filePath]) => `export const ${name}Shader = \`${getShaderCode(filePath)}\`;`)
.join('\n\n'); .join('\n\n');
@@ -200,7 +202,7 @@ const rollbar = cb => {
const assetsRev = cb => { const assetsRev = cb => {
const json = fs.readFileSync('dist/browser/rev-manifest.json', 'utf8'); const json = fs.readFileSync('dist/browser/rev-manifest.json', 'utf8');
const data = _.mapValues(JSON.parse(json), value => value.replace(/^\S+-([a-f0-9]{10})\.\S+$/, '$1')); const data = _.mapValues(JSON.parse(json), value => value.replace(/^\S+-([a-f0-9]{10})\.\S+$/, '$1'));
const code = `export const REV: { [key: string]: string; } = ${JSON.stringify(data, null, 4)};`; const code = `export const REV: { [key: string]: string; } = ${JSON.stringify(data, null, 2)};`;
fs.writeFile('src/ts/generated/rev.ts', lintCode(code), 'utf8', cb); fs.writeFile('src/ts/generated/rev.ts', lintCode(code), 'utf8', cb);
}; };
+12 -7
View File
@@ -26,7 +26,8 @@ export function createSupporterChanges(entries: LogEntry[]): SupporterChange[] {
if (current.level > prev.level) { if (current.level > prev.level) {
current.icon = faCaretSquareUp; current.icon = faCaretSquareUp;
current.class = 'text-info'; current.class = 'text-info';
} else if (current.level < prev.level) { }
else if (current.level < prev.level) {
current.icon = faCaretSquareDown; current.icon = faCaretSquareDown;
current.class = 'text-info'; current.class = 'text-info';
} }
@@ -49,7 +50,6 @@ function formatChatLine(l: string): HTMLElement {
// 00:00:01 [merged][dev][Autumn Leafs][ignored] hello world // 00:00:01 [merged][dev][Autumn Leafs][ignored] hello world
// 00:00:01 [merged][dev][main][Autumn Leafs][ignored] hello world // 00:00:01 [merged][dev][main][Autumn Leafs][ignored] hello world
/* tslint:disable:max-line-length */
const regex = /^([0-9:]+) (\[(?:merged|\d+|\d+:merged|[a-z0-9]{24})\])?\[([a-z0-9_-]+)\](?:\[([a-z0-9_-]+)\])?((?:\[.*?\])?)(?:\[(muted|ignored|ignorepub)\])?\t(.*)$/; const regex = /^([0-9:]+) (\[(?:merged|\d+|\d+:merged|[a-z0-9]{24})\])?\[([a-z0-9_-]+)\](?:\[([a-z0-9_-]+)\])?((?:\[.*?\])?)(?:\[(muted|ignored|ignorepub)\])?\t(.*)$/;
const m = regex.exec(l); const m = regex.exec(l);
@@ -69,7 +69,8 @@ function formatChatLine(l: string): HTMLElement {
textNode(' '), textNode(' '),
element('a', 'chat-translate', [], undefined, { click: translateChat }), element('a', 'chat-translate', [], undefined, { click: translateChat }),
]); ]);
} else { }
else {
return element('div', '', [textNode(highlightWords(l))]); return element('div', '', [textNode(highlightWords(l))]);
} }
} }
@@ -104,13 +105,17 @@ export function formatChat(chat: string): HTMLElement[] {
function getMessageTag(message: string) { function getMessageTag(message: string) {
if (/^\/p /.test(message)) { if (/^\/p /.test(message)) {
return 'party'; return 'party';
} else if (/^\/w /.test(message)) { }
else if (/^\/w /.test(message)) {
return 'whisper'; return 'whisper';
} else if (/^\/s[s123] /.test(message)) { }
else if (/^\/s[s123] /.test(message)) {
return 'supporter'; return 'supporter';
} else if (/^\//.test(message)) { }
else if (/^\//.test(message)) {
return 'command'; return 'command';
} else { }
else {
return 'none'; return 'none';
} }
} }
+48 -22
View File
@@ -225,8 +225,11 @@ export function deserializeActions(data: string): ButtonActionSlot[] {
try { try {
const json = JSON.parse(data); const json = JSON.parse(data);
return json.slice(0, ACTIONS_LIMIT).map(deserializeAction); return json.slice(0, ACTIONS_LIMIT).map(deserializeAction);
} catch (e) { }
DEVELOPMENT && console.error(e); catch (e) {
if (DEVELOPMENT) {
console.error(e);
}
return []; return [];
} }
} }
@@ -243,10 +246,13 @@ function serializeAction({ action }: ButtonActionSlot): any {
case 'entity': case 'entity':
return { ent: action.entity }; return { ent: action.entity };
default: default:
DEVELOPMENT && console.warn(`Missing serialization for ${JSON.stringify(action)}`); if (DEVELOPMENT) {
console.warn(`Missing serialization for ${JSON.stringify(action)}`);
}
return null; return null;
} }
} else { }
else {
return null; return null;
} }
} }
@@ -255,15 +261,21 @@ function deserializeAction(data: any): ButtonActionSlot {
if (data) { if (data) {
if ('act' in data || 'action' in data) { if ('act' in data || 'action' in data) {
return { action: getActionAction(data.act || data.action) }; return { action: getActionAction(data.act || data.action) };
} else if ('cmd' in data || 'command' in data) { }
else if ('cmd' in data || 'command' in data) {
return { action: getCommandAction(data.cmd || data.command) }; return { action: getCommandAction(data.cmd || data.command) };
} else if ('exp' in data || 'expression' in data) { }
else if ('exp' in data || 'expression' in data) {
const expression = decodeExpression(data.exp || data.expression | 0); const expression = decodeExpression(data.exp || data.expression | 0);
return { action: expressionButtonAction(expression) }; return { action: expressionButtonAction(expression) };
} else if ('ent' in data || 'entity' in data) { }
else if ('ent' in data || 'entity' in data) {
return { action: entityButtonAction(data.ent || data.entity) }; return { action: entityButtonAction(data.ent || data.entity) };
} else { }
DEVELOPMENT && console.warn(`Missing deserialization for ${JSON.stringify(data)}`); else {
if (DEVELOPMENT) {
console.warn(`Missing deserialization for ${JSON.stringify(data)}`);
}
} }
} }
@@ -281,7 +293,8 @@ export function useAction(game: PonyTownGame, action: ButtonAction | undefined)
case 'action': case 'action':
if (action.sendAction) { if (action.sendAction) {
game.send(server => server.action(action.sendAction)); game.send(server => server.action(action.sendAction));
} else { }
else {
switch (action.action) { switch (action.action) {
case 'boop': case 'boop':
boopAction(game); boopAction(game);
@@ -336,7 +349,8 @@ export function useAction(game: PonyTownGame, action: ButtonAction | undefined)
function shouldRedrawAction(action: ButtonAction | undefined, state: any, game: PonyTownGame) { function shouldRedrawAction(action: ButtonAction | undefined, state: any, game: PonyTownGame) {
if (action !== state.action) { if (action !== state.action) {
return true; return true;
} else if (action) { }
else if (action) {
switch (action.type) { switch (action.type) {
case 'action': { case 'action': {
switch (action.action) { switch (action.action) {
@@ -353,7 +367,8 @@ function shouldRedrawAction(action: ButtonAction | undefined, state: any, game:
default: default:
return false; return false;
} }
} else { }
else {
return false; return false;
} }
} }
@@ -373,13 +388,15 @@ export function drawAction(canvas: HTMLCanvasElement, action: ButtonAction | und
state.action = 0; state.action = 0;
} }
if (!spriteSheetsLoaded || !shouldRedrawAction(action, state, game)) if (!spriteSheetsLoaded || !shouldRedrawAction(action, state, game)) {
return; return;
}
const context = canvas.getContext('2d'); const context = canvas.getContext('2d');
if (!context) if (!context) {
return; return;
}
state.action = action; state.action = action;
@@ -412,10 +429,12 @@ export function drawAction(canvas: HTMLCanvasElement, action: ButtonAction | und
if (hasFlag(extra, ExpressionExtra.Cry)) { if (hasFlag(extra, ExpressionExtra.Cry)) {
batch.drawSprite(sprites.emote_cry2.frames[4], WHITE, defaultPalette, headX, headY); batch.drawSprite(sprites.emote_cry2.frames[4], WHITE, defaultPalette, headX, headY);
} else if (hasFlag(extra, ExpressionExtra.Tears)) { }
else if (hasFlag(extra, ExpressionExtra.Tears)) {
batch.drawSprite(sprites.emote_tears.frames[0], WHITE, defaultPalette, headX, headY); batch.drawSprite(sprites.emote_tears.frames[0], WHITE, defaultPalette, headX, headY);
} }
} else { }
else {
const color = parseColor(ACTION_EXPRESSION_BG); const color = parseColor(ACTION_EXPRESSION_BG);
batch.drawRect(color, 0, 3, 15, 5); batch.drawRect(color, 0, 3, 15, 5);
batch.drawRect(color, 0, 8, 3, 1); batch.drawRect(color, 0, 8, 3, 1);
@@ -449,9 +468,12 @@ export function drawAction(canvas: HTMLCanvasElement, action: ButtonAction | und
state.draw = action.action === 'up' ? getUpDrawFunc(game) : getDownDrawFunc(game); state.draw = action.action === 'up' ? getUpDrawFunc(game) : getDownDrawFunc(game);
buffer = drawCanvasCached(`action:${action.action}:${state.draw}`, batch => { buffer = drawCanvasCached(`action:${action.action}:${state.draw}`, batch => {
state.draw && getDrawFuncByName(state.draw)(batch); if (state.draw) {
getDrawFuncByName(state.draw)(batch);
}
}); });
} else { }
else {
buffer = drawCanvasCached(`action:${action.action}`, batch => { buffer = drawCanvasCached(`action:${action.action}`, batch => {
switch (action.action) { switch (action.action) {
case 'boop': { case 'boop': {
@@ -662,9 +684,11 @@ function getUpDrawFunc(game: PonyTownGame) {
if (player) { if (player) {
if (isPonyLying(player)) { if (isPonyLying(player)) {
return 'sit'; return 'sit';
} else if (isPonySitting(player)) { }
else if (isPonySitting(player)) {
return 'stand'; return 'stand';
} else if (isPonyStanding(player) && canPonyFly(player)) { }
else if (isPonyStanding(player) && canPonyFly(player)) {
return 'fly'; return 'fly';
} }
} }
@@ -678,9 +702,11 @@ function getDownDrawFunc(game: PonyTownGame) {
if (player) { if (player) {
if (isPonySitting(player)) { if (isPonySitting(player)) {
return 'lie'; return 'lie';
} else if (isPonyStanding(player)) { }
else if (isPonyStanding(player)) {
return 'sit'; return 'sit';
} else if (isPonyFlying(player)) { }
else if (isPonyFlying(player)) {
return 'stand'; return 'stand';
} }
} }
+6 -2
View File
@@ -51,7 +51,9 @@ export class ClientActions extends ClientActionsTemplate {
this.apply(() => this.gameService.disconnected()); this.apply(() => this.gameService.disconnected());
} }
invalidVersion() { invalidVersion() {
DEVELOPMENT && !TESTS && console.error('Invalid version'); if (DEVELOPMENT && !TESTS) {
console.error('Invalid version');
}
} }
// @Method({ binary: [Bin.U32] }) // @Method({ binary: [Bin.U32] })
queue(place: number) { queue(place: number) {
@@ -182,7 +184,9 @@ export class ClientActions extends ClientActionsTemplate {
this.game.nextFriendsCRC = 0; this.game.nextFriendsCRC = 0;
break; break;
default: default:
DEVELOPMENT && !TESTS && console.error(`actionParam: Invalid action: ${action}`); if (DEVELOPMENT && !TESTS) {
console.error(`actionParam: Invalid action: ${action}`);
}
} }
} }
// @Method({ binary: [Bin.U8] }>) // @Method({ binary: [Bin.U8] }>)
+2 -1
View File
@@ -20,7 +20,8 @@ export class ClientAdminActions extends ClientAdminActionsTemplate {
if (model) { if (model) {
model.update(id, update); model.update(id, update);
} else { }
else {
console.error(`Invalid model type "${type}"`); console.error(`Invalid model type "${type}"`);
} }
} }
+36 -18
View File
@@ -39,7 +39,8 @@ function isMultipleMatch(message: string, last: string): boolean {
} }
return message === current.substr(0, SAY_MAX_LENGTH); return message === current.substr(0, SAY_MAX_LENGTH);
} else { }
else {
return false; return false;
} }
} }
@@ -53,9 +54,11 @@ function isTrailingMatch(message: string, last: string) {
if (message.length > last.length && last.length > minMessageLength) { if (message.length > last.length && last.length > minMessageLength) {
return checkTrailing(message, last); return checkTrailing(message, last);
} else if (message.length < last.length && message.length > minMessageLength) { }
else if (message.length < last.length && message.length > minMessageLength) {
return checkTrailing(last, message); return checkTrailing(last, message);
} else { }
else {
return false; return false;
} }
} }
@@ -63,7 +66,8 @@ function isTrailingMatch(message: string, last: string) {
export function isSpamMessage(message: string, lastMessages: string[]): boolean { export function isSpamMessage(message: string, lastMessages: string[]): boolean {
if (!/^\//.test(message) && lastMessages.length) { if (!/^\//.test(message) && lastMessages.length) {
return lastMessages.some(last => message === last || isMultipleMatch(message, last) || isTrailingMatch(message, last)); return lastMessages.some(last => message === last || isMultipleMatch(message, last) || isTrailingMatch(message, last));
} else { }
else {
return false; return false;
} }
} }
@@ -154,7 +158,8 @@ export function readFileAsText(file: File) {
export function isFileSaverSupported() { export function isFileSaverSupported() {
try { try {
return !!new Blob; return !!new Blob;
} catch { }
catch {
return false; return false;
} }
} }
@@ -167,13 +172,15 @@ export function setIsIncognitoMode(value: boolean) {
/* istanbul ignore next */ /* istanbul ignore next */
function checkIncognitoMode(wnd: any) { function checkIncognitoMode(wnd: any) {
if (!wnd || !wnd.chrome) if (!wnd || !wnd.chrome) {
return; return;
}
const fs = wnd.RequestFileSystem || wnd.webkitRequestFileSystem; const fs = wnd.RequestFileSystem || wnd.webkitRequestFileSystem;
if (!fs) if (!fs){
return; return;
}
fs(wnd.TEMPORARY, 100, () => { }, () => isInIncognitoMode = true); fs(wnd.TEMPORARY, 100, () => { }, () => isInIncognitoMode = true);
} }
@@ -202,7 +209,8 @@ export function isStandalone() {
export function supportsLetAndConst() { export function supportsLetAndConst() {
try { try {
return (new Function('let x = true; return x;'))(); return (new Function('let x = true; return x;'))();
} catch { }
catch {
return false; return false;
} }
} }
@@ -230,7 +238,8 @@ export function registerServiceWorker(url: string, onUpdate: () => void) {
} }
}); });
} }
} catch (e) { }
catch (e) {
console.error(e); console.error(e);
} }
} }
@@ -244,7 +253,8 @@ export function unregisterServiceWorker() {
registration.unregister(); registration.unregister();
} }
}); });
} else { }
else {
return Promise.resolve(); return Promise.resolve();
} }
} }
@@ -271,7 +281,8 @@ export function updateRangeIndicator(range: number | undefined, { player, scale,
e.style.top = `${-h / 2}px`; e.style.top = `${-h / 2}px`;
e.style.transform = `translate3d(${x}px, ${y}px, 0)`; e.style.transform = `translate3d(${x}px, ${y}px, 0)`;
e.style.display = 'block'; e.style.display = 'block';
} else { }
else {
e.style.display = 'none'; e.style.display = 'none';
} }
} }
@@ -283,7 +294,8 @@ export function checkIframeKey(iframeId: string, expectedKey: string) {
const doc = iframe && iframe.contentWindow && iframe.contentWindow.document; const doc = iframe && iframe.contentWindow && iframe.contentWindow.document;
const key = doc && doc.body && doc.body.getAttribute('data-key'); const key = doc && doc.body && doc.body.getAttribute('data-key');
return key === expectedKey; return key === expectedKey;
} catch (e) { }
catch (e) {
if (DEVELOPMENT) { if (DEVELOPMENT) {
console.error(e); console.error(e);
} }
@@ -333,9 +345,11 @@ export function isSupporterOrPastSupporter(account: AccountData | undefined) {
export function supporterTitle(account: AccountData | undefined) { export function supporterTitle(account: AccountData | undefined) {
if (account && account.supporter) { if (account && account.supporter) {
return `Supporter Tier ${account.supporter}`; return `Supporter Tier ${account.supporter}`;
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) { }
else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
return 'Past supporter'; return 'Past supporter';
} else { }
else {
return ''; return '';
} }
} }
@@ -343,9 +357,11 @@ export function supporterTitle(account: AccountData | undefined) {
export function supporterClass(account: AccountData | undefined) { export function supporterClass(account: AccountData | undefined) {
if (account && account.supporter) { if (account && account.supporter) {
return `supporter-${account.supporter}`; return `supporter-${account.supporter}`;
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) { }
else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
return 'supporter-past'; return 'supporter-past';
} else { }
else {
return 'd-none'; return 'd-none';
} }
} }
@@ -353,9 +369,11 @@ export function supporterClass(account: AccountData | undefined) {
export function supporterRewards(account: AccountData | undefined) { export function supporterRewards(account: AccountData | undefined) {
if (account && account.supporter) { if (account && account.supporter) {
return SUPPORTER_REWARDS[account.supporter]; return SUPPORTER_REWARDS[account.supporter];
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) { }
else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
return PAST_SUPPORTER_REWARDS; return PAST_SUPPORTER_REWARDS;
} else { }
else {
return SUPPORTER_REWARDS[0]; return SUPPORTER_REWARDS[0];
} }
} }
+2 -1
View File
@@ -46,7 +46,8 @@ export function socketOptions(): ClientOptions {
const buffer = toByteArray(options); const buffer = toByteArray(options);
const reader = createBinaryReader(buffer); const reader = createBinaryReader(buffer);
return readObject(reader); return readObject(reader);
} else { }
else {
throw new Error('Missing socket options'); throw new Error('Missing socket options');
} }
} }
+58 -24
View File
@@ -31,11 +31,13 @@ function drawEntities(batch: PaletteSpriteBatch, entities: Entity[], camera: Cam
batch.depth = -batch.depth; batch.depth = -batch.depth;
drawPonyEntity(batch, entity as Pony, options); drawPonyEntity(batch, entity as Pony, options);
entitiesDrawn++; entitiesDrawn++;
} else if (entity.draw !== undefined) { }
else if (entity.draw !== undefined) {
entity.draw(batch, options); entity.draw(batch, options);
entitiesDrawn++; entitiesDrawn++;
} }
} else { }
else {
if (entity.type === PONY_TYPE) { if (entity.type === PONY_TYPE) {
const pony = entity as Pony; const pony = entity as Pony;
@@ -62,7 +64,8 @@ export function drawEntityLights(batch: SpriteBatch, entities: Entity[], camera:
if (isBoundsVisible(camera, entity.lightBounds, entity.x, entity.y) && (!isHidden(entity) || drawHidden)) { if (isBoundsVisible(camera, entity.lightBounds, entity.x, entity.y) && (!isHidden(entity) || drawHidden)) {
if (entity.type === PONY_TYPE) { if (entity.type === PONY_TYPE) {
drawPonyEntityLight(batch, entity as Pony, options); drawPonyEntityLight(batch, entity as Pony, options);
} else { }
else {
entity.drawLight!(batch, options); entity.drawLight!(batch, options);
} }
++drawn; ++drawn;
@@ -85,7 +88,8 @@ export function drawEntityLightSprites(batch: SpriteBatch, entities: Entity[], c
batch.depth = entity.depth; batch.depth = entity.depth;
if (entity.type === PONY_TYPE) { if (entity.type === PONY_TYPE) {
drawPonyEntityLightSprite(batch, entity as Pony, options); drawPonyEntityLightSprite(batch, entity as Pony, options);
} else { }
else {
entity.drawLightSprite!(batch, options); entity.drawLightSprite!(batch, options);
} }
++drawn; ++drawn;
@@ -100,7 +104,8 @@ export function hasDrawLight(entity: Entity) {
const pony = entity as Pony; const pony = entity as Pony;
return (pony.ponyState.holding !== undefined && pony.ponyState.holding.drawLight !== undefined) || return (pony.ponyState.holding !== undefined && pony.ponyState.holding.drawLight !== undefined) ||
((pony.state & EntityState.Magic) !== 0); ((pony.state & EntityState.Magic) !== 0);
} else { }
else {
return entity.drawLight !== undefined; return entity.drawLight !== undefined;
} }
} }
@@ -109,7 +114,8 @@ export function hasLightSprite(entity: Entity) {
if (entity.type === PONY_TYPE) { if (entity.type === PONY_TYPE) {
const pony = entity as Pony; const pony = entity as Pony;
return (pony.ponyState.holding !== undefined && pony.ponyState.holding.drawLightSprite !== undefined); return (pony.ponyState.holding !== undefined && pony.ponyState.holding.drawLightSprite !== undefined);
} else { }
else {
return entity.drawLightSprite !== undefined; return entity.drawLightSprite !== undefined;
} }
} }
@@ -118,25 +124,39 @@ export function drawMap(
batch: PaletteSpriteBatch, map: WorldMap, camera: Camera, player: Pony, batch: PaletteSpriteBatch, map: WorldMap, camera: Camera, player: Pony,
options: DrawOptions, tileSets: TileSets, selectedEntities: Entity[], options: DrawOptions, tileSets: TileSets, selectedEntities: Entity[],
) { ) {
TIMING && timeStart('forEachRegion'); if (TIMING) {
timeStart('forEachRegion');
}
batch.depth = 1.0; batch.depth = 1.0;
if (BETA && options.engine === Engine.Whiteness) { if (BETA && options.engine === Engine.Whiteness) {
batch.drawRect(WHITE, 0, 0, toScreenX(map.width), toScreenY(map.height)); batch.drawRect(WHITE, 0, 0, toScreenX(map.width), toScreenY(map.height));
} else if (BETA && options.engine === Engine.LayeredTiles) { }
else if (BETA && options.engine === Engine.LayeredTiles) {
forEachRegion(map, region => drawTilesNew(batch, region, camera, map, tileSets, options)); forEachRegion(map, region => drawTilesNew(batch, region, camera, map, tileSets, options));
} else { }
else {
forEachRegion(map, region => drawTiles(batch, region, camera, map, tileSets, options)); forEachRegion(map, region => drawTiles(batch, region, camera, map, tileSets, options));
} }
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
TIMING && timeStart('sortEntities'); if (TIMING) {
timeStart('sortEntities');
}
sortEntities(map.entitiesDrawable); sortEntities(map.entitiesDrawable);
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
TIMING && timeStart('drawEntities'); if (TIMING) {
timeStart('drawEntities');
}
const entitiesDrawn = drawEntities(batch, map.entitiesDrawable, camera, options); const entitiesDrawn = drawEntities(batch, map.entitiesDrawable, camera, options);
batch.depth = 1.0; batch.depth = 1.0;
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
if (BETA || TOOLS) { if (BETA || TOOLS) {
forEachRegion(map, region => drawTilesDebugInfo(batch, region, camera, options)); forEachRegion(map, region => drawTilesDebugInfo(batch, region, camera, options));
@@ -179,10 +199,18 @@ function drawDebugHelpers(batch: PaletteSpriteBatch, entities: Entity[], options
for (const e of entities) { for (const e of entities) {
batch.globalAlpha = 0.3; batch.globalAlpha = 0.3;
show.bounds && drawBounds(batch, e, e.bounds, ORANGE); if (show.bounds) {
show.cover && drawBounds(batch, e, e.coverBounds, BLUE); drawBounds(batch, e, e.bounds, ORANGE);
show.interact && drawBounds(batch, e, e.interactBounds, PURPLE); }
show.trigger && drawWorldBounds(batch, e, e.triggerBounds, CYAN); if (show.cover) {
drawBounds(batch, e, e.coverBounds, BLUE);
}
if (show.interact) {
drawBounds(batch, e, e.interactBounds, PURPLE);
}
if (show.trigger) {
drawWorldBounds(batch, e, e.triggerBounds, CYAN);
}
if (show.collider) { if (show.collider) {
batch.globalAlpha = 0.5; batch.globalAlpha = 0.5;
@@ -224,16 +252,19 @@ function drawDebugInWater(batch: PaletteSpriteBatch, map: WorldMap, camera: Came
const cameraTop = camera.actualY; const cameraTop = camera.actualY;
const cameraBottom = camera.actualY + camera.h; const cameraBottom = camera.actualY + camera.h;
if (sx > cameraRight || sy > cameraBottom || (sx + w) < cameraLeft || (sy + h) < cameraTop) if (sx > cameraRight || sy > cameraBottom || (sx + w) < cameraLeft || (sy + h) < cameraTop) {
return; return;
}
for (let y = 0; y < h; y++) { for (let y = 0; y < h; y++) {
if ((sy + y + 1) < cameraTop || (sy + y) > cameraBottom) if ((sy + y + 1) < cameraTop || (sy + y) > cameraBottom) {
continue; continue;
}
for (let x = 0; x < w; x++) { for (let x = 0; x < w; x++) {
if ((sx + x + 1) < cameraLeft || (sx + x) > cameraRight) if ((sx + x + 1) < cameraLeft || (sx + x) > cameraRight) {
continue; continue;
}
const tx = x; const tx = x;
@@ -263,16 +294,19 @@ function drawDebugCollider(batch: PaletteSpriteBatch, map: WorldMap, camera: Cam
const cameraTop = camera.actualY; const cameraTop = camera.actualY;
const cameraBottom = camera.actualY + camera.h; const cameraBottom = camera.actualY + camera.h;
if (sx > cameraRight || sy > cameraBottom || (sx + w) < cameraLeft || (sy + h) < cameraTop) if (sx > cameraRight || sy > cameraBottom || (sx + w) < cameraLeft || (sy + h) < cameraTop) {
return; return;
}
for (let y = 0; y < h; y++) { for (let y = 0; y < h; y++) {
if ((sy + y + 1) < cameraTop || (sy + y) > cameraBottom) if ((sy + y + 1) < cameraTop || (sy + y) > cameraBottom) {
continue; continue;
}
for (let x = 0; x < w; x++) { for (let x = 0; x < w; x++) {
if ((sx + x + 1) < cameraLeft || (sx + x) > cameraRight) if ((sx + x + 1) < cameraLeft || (sx + x) > cameraRight) {
continue; continue;
}
const tx = x; const tx = x;
+219 -87
View File
@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import { Injectable, NgZone } from '@angular/core'; import { Injectable, NgZone } from '@angular/core';
import { Subject, BehaviorSubject } from 'rxjs'; import { Subject, BehaviorSubject } from 'rxjs';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
@@ -370,7 +371,8 @@ export class PonyTownGame implements Game {
send<T>(action: (server: IServerActions) => T) { send<T>(action: (server: IServerActions) => T) {
if (this.socket && this.socket.isConnected) { if (this.socket && this.socket.isConnected) {
return action(this.socket.server); return action(this.socket.server);
} else { }
else {
return undefined; return undefined;
} }
} }
@@ -385,11 +387,13 @@ export class PonyTownGame implements Game {
this.setScale(Math.max(1, this.scale - 1)); this.setScale(Math.max(1, this.scale - 1));
} }
select(pony: Pony | undefined) { select(pony: Pony | undefined) {
if (this.selected === pony) if (this.selected === pony) {
return; return;
}
if (pony && isHidden(pony) && !this.mod) if (pony && isHidden(pony) && !this.mod) {
return; return;
}
this.zone.run(() => { this.zone.run(() => {
if (this.selected) { if (this.selected) {
@@ -400,7 +404,8 @@ export class PonyTownGame implements Game {
if (pony && !pony.info && !pony.palettePonyInfo) { if (pony && !pony.info && !pony.palettePonyInfo) {
this.send(server => server.select(pony.id, SelectFlags.FetchEx | SelectFlags.FetchInfo)); this.send(server => server.select(pony.id, SelectFlags.FetchEx | SelectFlags.FetchInfo));
} else { }
else {
this.sendSelected(); this.sendSelected();
} }
@@ -427,12 +432,16 @@ export class PonyTownGame implements Game {
if (!this.initialized) { if (!this.initialized) {
this.canvas.addEventListener('webglcontextlost', e => { this.canvas.addEventListener('webglcontextlost', e => {
e.preventDefault(); e.preventDefault();
DEVELOPMENT && console.warn('Context lost'); if (DEVELOPMENT) {
console.warn('Context lost');
}
this.errorReporter.captureEvent({ name: 'Context lost' }); this.errorReporter.captureEvent({ name: 'Context lost' });
}); });
this.canvas.addEventListener('webglcontextrestored', () => { this.canvas.addEventListener('webglcontextrestored', () => {
DEVELOPMENT && console.warn('Context restored'); if (DEVELOPMENT) {
console.warn('Context restored');
}
this.errorReporter.captureEvent({ name: 'Context restored' }); this.errorReporter.captureEvent({ name: 'Context restored' });
if (this.webgl) { if (this.webgl) {
@@ -573,7 +582,8 @@ export class PonyTownGame implements Game {
dir = -1; dir = -1;
} }
}, 1000 / 24); }, 1000 / 24);
} else { }
else {
let faceDir = 0; let faceDir = 0;
const state = this.player!.ponyState; const state = this.player!.ponyState;
@@ -643,7 +653,8 @@ export class PonyTownGame implements Game {
if (loseContext) { if (loseContext) {
loseContext.restoreContext(); loseContext.restoreContext();
loseContext = null; loseContext = null;
} else { }
else {
loseContext = this.webgl!.gl.getExtension('WEBGL_lose_context')!; loseContext = this.webgl!.gl.getExtension('WEBGL_lose_context')!;
loseContext.loseContext(); loseContext.loseContext();
} }
@@ -661,7 +672,8 @@ export class PonyTownGame implements Game {
const entity = entities[0]; const entity = entities[0];
const typeName = getEntityTypeName(entity.type); const typeName = getEntityTypeName(entity.type);
this.announce(`${typeName}${entities.length > 1 ? ` (1 of ${entities.length})` : ''}`); this.announce(`${typeName}${entities.length > 1 ? ` (1 of ${entities.length})` : ''}`);
} else { }
else {
this.announce('nothing'); this.announce('nothing');
} }
} }
@@ -705,7 +717,9 @@ export class PonyTownGame implements Game {
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
this.resized = true; this.resized = true;
DEVELOPMENT && log(`resized ${window.innerHeight} (${window.scrollY})`); if (DEVELOPMENT) {
log(`resized ${window.innerHeight} (${window.scrollY})`);
}
}); });
this.canvas.addEventListener('touchstart', () => this.audio.touch()); this.canvas.addEventListener('touchstart', () => this.audio.touch());
@@ -721,7 +735,8 @@ export class PonyTownGame implements Game {
if (this.socket) { if (this.socket) {
if (this.socket.isConnected) { if (this.socket.isConnected) {
this.socket.server.leave(); this.socket.server.leave();
} else { }
else {
this.socket.disconnect(); this.socket.disconnect();
} }
} }
@@ -767,10 +782,13 @@ export class PonyTownGame implements Game {
this.supporterPony = createPony(0, 0, SUPPORTER_PONY, palettes.defaultPalette, this.paletteManager); this.supporterPony = createPony(0, 0, SUPPORTER_PONY, palettes.defaultPalette, this.paletteManager);
this.discordPony = createPony(0, 0, DISCORD_PONY, palettes.defaultPalette, this.paletteManager); this.discordPony = createPony(0, 0, DISCORD_PONY, palettes.defaultPalette, this.paletteManager);
initializeToys(this.paletteManager); initializeToys(this.paletteManager);
} catch (e) { }
catch (e) {
this.errorReporter.captureEvent({ name: 'failed game.initWebGL', error: isErrorAlike(e) ? e.message : '', stack: isErrorAlike(e) ? e.stack : '' }); this.errorReporter.captureEvent({ name: 'failed game.initWebGL', error: isErrorAlike(e) ? e.message : '', stack: isErrorAlike(e) ? e.stack : '' });
this.releaseWebGL(); this.releaseWebGL();
DEVELOPMENT && console.error(e); if (DEVELOPMENT) {
console.error(e);
}
throw new Error(`Failed to initialize graphics device (${isErrorAlike(e) ? e.message : 'Unknown error'})`); throw new Error(`Failed to initialize graphics device (${isErrorAlike(e) ? e.message : 'Unknown error'})`);
} }
} }
@@ -781,8 +799,11 @@ export class PonyTownGame implements Game {
try { try {
this.paletteManager.dispose(this.webgl.gl); this.paletteManager.dispose(this.webgl.gl);
disposeWebGL(this.webgl); disposeWebGL(this.webgl);
} catch (e) { }
DEVELOPMENT && console.error(e); catch (e) {
if (DEVELOPMENT) {
console.error(e);
}
} }
this.webgl = undefined; this.webgl = undefined;
@@ -827,7 +848,8 @@ export class PonyTownGame implements Game {
startup(socket: ClientSocketService, mod: boolean) { startup(socket: ClientSocketService, mod: boolean) {
if (this.settings.account.actions) { if (this.settings.account.actions) {
this.actions = deserializeActions(this.settings.account.actions); this.actions = deserializeActions(this.settings.account.actions);
} else { }
else {
this.actions = createDefaultButtonActions(); this.actions = createDefaultButtonActions();
} }
@@ -860,21 +882,25 @@ export class PonyTownGame implements Game {
return this.scale * (integerPixelRatio() / pixelRatio()); return this.scale * (integerPixelRatio() / pixelRatio());
} }
update(delta: number, now: number, last: number) { update(delta: number, now: number, last: number) {
TIMING && timeStart('update'); if (TIMING) {
timeStart('update');
}
delta *= this.deltaMultiplier; delta *= this.deltaMultiplier;
const shiftSpeed = delta * 10; const shiftSpeed = delta * 10;
if (this.cameraShiftOn && this.camera.shiftRatio !== 1) { if (this.cameraShiftOn && this.camera.shiftRatio !== 1) {
this.camera.shiftRatio = Math.min(1, this.camera.shiftRatio + shiftSpeed); this.camera.shiftRatio = Math.min(1, this.camera.shiftRatio + shiftSpeed);
} else if (!this.cameraShiftOn && this.camera.shiftRatio !== 0) { }
else if (!this.cameraShiftOn && this.camera.shiftRatio !== 0) {
this.camera.shiftRatio = Math.max(0, this.camera.shiftRatio - shiftSpeed); this.camera.shiftRatio = Math.max(0, this.camera.shiftRatio - shiftSpeed);
} }
updateMap(this.map, delta); updateMap(this.map, delta);
if (!this.socket || !this.socket.isConnected || !this.element) if (!this.socket || !this.socket.isConnected || !this.element) {
return; return;
}
this.updateGameTime(delta); this.updateGameTime(delta);
@@ -986,7 +1012,8 @@ export class PonyTownGame implements Game {
if (hasFlag(this.map.flags, MapFlags.EditableEntities)) { if (hasFlag(this.map.flags, MapFlags.EditableEntities)) {
if (player.hold === removeEntitiesTool.type) { if (player.hold === removeEntitiesTool.type) {
this.highlightEntity = pickEntities(this.map, hover, true, false, true)[0]; this.highlightEntity = pickEntities(this.map, hover, true, false, true)[0];
} else if (player.hold === placeEntitiesTool.type) { }
else if (player.hold === placeEntitiesTool.type) {
if (!isOutsideMap(hover.x, hover.y, this.map)) { if (!isOutsideMap(hover.x, hover.y, this.map)) {
const { type } = placeableEntities[this.placeEntity]; const { type } = placeableEntities[this.placeEntity];
let { x, y } = hover; let { x, y } = hover;
@@ -1011,38 +1038,48 @@ export class PonyTownGame implements Game {
if (BETA && this.editor.selectingEntities) { if (BETA && this.editor.selectingEntities) {
editorSelectEntities(this, hover, shift); editorSelectEntities(this, hover, shift);
} else if (pickedEntity && (!holdingTool || !editableMap || hasFlag(pickedEntity.flags, EntityFlags.IgnoreTool))) { }
else if (pickedEntity && (!holdingTool || !editableMap || hasFlag(pickedEntity.flags, EntityFlags.IgnoreTool))) {
if (pickedEntity.type === PONY_TYPE) { if (pickedEntity.type === PONY_TYPE) {
this.select(pickedEntity as Pony); this.select(pickedEntity as Pony);
} else if (entityInRange(pickedEntity, player)) { }
else if (entityInRange(pickedEntity, player)) {
server.interact(pickedEntity.id); server.interact(pickedEntity.id);
} }
} else if (BETA && this.editor.tile !== -1) { }
else if (BETA && this.editor.tile !== -1) {
if (this.editor.brushSize > 1) { if (this.editor.brushSize > 1) {
const x = Math.floor((hover.x - (this.editor.brushSize / 2))); const x = Math.floor((hover.x - (this.editor.brushSize / 2)));
const y = Math.floor((hover.y - (this.editor.brushSize / 2))); const y = Math.floor((hover.y - (this.editor.brushSize / 2)));
server.editorAction({ type: 'tile', x, y, tile: this.editor.tile, size: this.editor.brushSize }); server.editorAction({ type: 'tile', x, y, tile: this.editor.tile, size: this.editor.brushSize });
} else { }
else {
const x = hover.x | 0; const x = hover.x | 0;
const y = hover.y | 0; const y = hover.y | 0;
const type = this.editor.tile === getTile(this.map, hover.x, hover.y) ? TileType.Dirt : this.editor.tile; const type = this.editor.tile === getTile(this.map, hover.x, hover.y) ? TileType.Dirt : this.editor.tile;
server.changeTile(x, y, type); server.changeTile(x, y, type);
} }
} else if (player.hold === changeTileTool.type && hasFlag(this.map.flags, MapFlags.EditableTiles)) { }
else if (player.hold === changeTileTool.type && hasFlag(this.map.flags, MapFlags.EditableTiles)) {
const x = hover.x | 0; const x = hover.x | 0;
const y = hover.y | 0; const y = hover.y | 0;
server.changeTile(x, y, houseTiles[this.placeTile].type); server.changeTile(x, y, houseTiles[this.placeTile].type);
} else if (player.hold === toggleWallsTool.type && hasFlag(this.map.flags, MapFlags.EditableWalls)) { }
else if (player.hold === toggleWallsTool.type && hasFlag(this.map.flags, MapFlags.EditableWalls)) {
toggleWall(this, hover); toggleWall(this, hover);
} else if (holdingRemoveTool && this.highlightEntity && editableMap) { }
else if (holdingRemoveTool && this.highlightEntity && editableMap) {
const id = this.highlightEntity.id; const id = this.highlightEntity.id;
this.send(server => server.actionParam(Action.RemoveEntity, id)); this.send(server => server.actionParam(Action.RemoveEntity, id));
} else if (holdingPlaceTool && this.highlightEntity && editableMap) { }
else if (holdingPlaceTool && this.highlightEntity && editableMap) {
const { x, y, type } = this.highlightEntity; const { x, y, type } = this.highlightEntity;
this.send(server => server.actionParam(Action.PlaceEntity, { x, y, type })); this.send(server => server.actionParam(Action.PlaceEntity, { x, y, type }));
} else if (this.selected) { }
else if (this.selected) {
this.select(undefined); this.select(undefined);
} else if (hasFlag(this.map.flags, MapFlags.EdibleGrass)) { }
else if (hasFlag(this.map.flags, MapFlags.EdibleGrass)) {
const tile = getTile(this.map, hover.x, hover.y); const tile = getTile(this.map, hover.x, hover.y);
if (isValidTile(tile) && distanceXY(player.x, player.y, hover.x, hover.y) < TILE_CHANGE_RANGE) { if (isValidTile(tile) && distanceXY(player.x, player.y, hover.x, hover.y) < TILE_CHANGE_RANGE) {
@@ -1051,7 +1088,8 @@ export class PonyTownGame implements Game {
let type = tile === TileType.Grass ? TileType.Dirt : TileType.Grass; let type = tile === TileType.Grass ? TileType.Dirt : TileType.Grass;
server.changeTile(x, y, type); server.changeTile(x, y, type);
} }
} else if (DEVELOPMENT && this.engine === Engine.LayeredTiles && this.editor.elevation) { }
else if (DEVELOPMENT && this.engine === Engine.LayeredTiles && this.editor.elevation) {
const value = getElevation(this.map, hover.x, hover.y); const value = getElevation(this.map, hover.x, hover.y);
setElevation(this.map, hover.x, hover.y, clamp(this.editor.elevation === 'up' ? value + 1 : value - 1, 0, 10)); setElevation(this.map, hover.x, hover.y, clamp(this.editor.elevation === 'up' ? value + 1 : value - 1, 0, 10));
} }
@@ -1060,7 +1098,8 @@ export class PonyTownGame implements Game {
if (BETA && input.wasPressed(Key.MOUSE_BUTTON2)) { if (BETA && input.wasPressed(Key.MOUSE_BUTTON2)) {
if (this.editor.selectingEntities) { if (this.editor.selectingEntities) {
editorMoveEntities(this, hover); editorMoveEntities(this, hover);
} else if (this.mod) { }
else if (this.mod) {
toggleWall(this, hover); toggleWall(this, hover);
} }
} }
@@ -1078,10 +1117,12 @@ export class PonyTownGame implements Game {
const action = input.wheelY < 0 ? Action.SwitchTool : Action.SwitchToolRev; const action = input.wheelY < 0 ? Action.SwitchTool : Action.SwitchToolRev;
this.send(server => server.action(action)); this.send(server => server.action(action));
} }
} else { }
else {
if (this.player.hold === placeEntitiesTool.type) { if (this.player.hold === placeEntitiesTool.type) {
this.changePlaceEntity(input.wheelY < 0); this.changePlaceEntity(input.wheelY < 0);
} else if (this.player.hold === changeTileTool.type) { }
else if (this.player.hold === changeTileTool.type) {
this.changePlaceTile(input.wheelY < 0); this.changePlaceTile(input.wheelY < 0);
} }
} }
@@ -1144,7 +1185,9 @@ export class PonyTownGame implements Game {
} }
this.updateSocketStats(delta); this.updateSocketStats(delta);
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
if (DEVELOPMENT && LOG_POSITION) { if (DEVELOPMENT && LOG_POSITION) {
if (this.player) { if (this.player) {
@@ -1159,7 +1202,8 @@ export class PonyTownGame implements Game {
if (Math.abs(this.targetBaseTime - baseTime) < timeDelta) { if (Math.abs(this.targetBaseTime - baseTime) < timeDelta) {
this.baseTime = this.targetBaseTime; this.baseTime = this.targetBaseTime;
} else { }
else {
this.baseTime = baseTime; this.baseTime = baseTime;
} }
} }
@@ -1188,7 +1232,8 @@ export class PonyTownGame implements Game {
if (initial) { if (initial) {
this.baseTime = this.targetBaseTime = baseTime; this.baseTime = this.targetBaseTime = baseTime;
} else { }
else {
this.targetBaseTime = baseTime; this.targetBaseTime = baseTime;
} }
@@ -1218,11 +1263,14 @@ export class PonyTownGame implements Game {
redrawActionButtons(this.actionsChanged); redrawActionButtons(this.actionsChanged);
this.actionsChanged = false; this.actionsChanged = false;
if (!this.webgl) if (!this.webgl) {
return; return;
}
if (this.webgl.gl.isContextLost()) { if (this.webgl.gl.isContextLost()) {
DEVELOPMENT && console.warn('Context is lost'); if (DEVELOPMENT) {
console.warn('Context is lost');
}
return; return;
} }
@@ -1247,16 +1295,21 @@ export class PonyTownGame implements Game {
const { gl, frameBuffer, frameBuffer2, spriteBatch, paletteBatch, palettes, failedFBO, const { gl, frameBuffer, frameBuffer2, spriteBatch, paletteBatch, palettes, failedFBO,
mergeShader, paletteShader, spriteShader, spriteShaderWithColor, lightShader } = this.webgl; mergeShader, paletteShader, spriteShader, spriteShaderWithColor, lightShader } = this.webgl;
TIMING && timeStart('draw'); if (TIMING) {
timeStart('draw');
}
TIMING && timeStart('draw init'); if (TIMING) {
timeStart('draw init');
}
let lightColor = WHITE; let lightColor = WHITE;
let shadowColor = 0; let shadowColor = 0;
if (this.map.type === MapType.Cave) { if (this.map.type === MapType.Cave) {
lightColor = CAVE_LIGHT; lightColor = CAVE_LIGHT;
shadowColor = CAVE_SHADOW; shadowColor = CAVE_SHADOW;
} else { }
else {
lightColor = getLightColor(this.lightData, this.time); lightColor = getLightColor(this.lightData, this.time);
shadowColor = getShadowColor(this.lightData, this.time); shadowColor = getShadowColor(this.lightData, this.time);
} }
@@ -1291,17 +1344,27 @@ export class PonyTownGame implements Game {
} }
ortho(this.fboMatrix, 0, gl.drawingBufferWidth / actualScale, gl.drawingBufferHeight / actualScale, 0, 0, 1000, false); ortho(this.fboMatrix, 0, gl.drawingBufferWidth / actualScale, gl.drawingBufferHeight / actualScale, 0, 0, 1000, false);
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
TIMING && timeStart('ensureAllVisiblePon...'); if (TIMING) {
timeStart('ensureAllVisiblePon...');
}
ensureAllVisiblePoniesAreDecoded(this.map, camera, this.paletteManager); ensureAllVisiblePoniesAreDecoded(this.map, camera, this.paletteManager);
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
TIMING && timeStart('commit+invalidatePalettes'); if (TIMING) {
timeStart('commit+invalidatePalettes');
}
if (this.paletteManager.commit(gl)) { if (this.paletteManager.commit(gl)) {
invalidatePalettes(this.map.entitiesDrawable); invalidatePalettes(this.map.entitiesDrawable);
} }
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
if (this.settings.browser.brightNight) { if (this.settings.browser.brightNight) {
lerpColor(light, white, 0.3); lerpColor(light, white, 0.3);
@@ -1310,9 +1373,13 @@ export class PonyTownGame implements Game {
// you'd draw directly onto the screen only when there's no framebuffer // you'd draw directly onto the screen only when there's no framebuffer
// or the graphics is low and framebuffer size matches screen size // or the graphics is low and framebuffer size matches screen size
TIMING && timeStart('initializeFrameBuffers'); if (TIMING) {
timeStart('initializeFrameBuffers');
}
this.initializeFrameBuffers(this.webgl, width, height, this.settings.browser.graphicsQuality === GraphicsQuality.High); this.initializeFrameBuffers(this.webgl, width, height, this.settings.browser.graphicsQuality === GraphicsQuality.High);
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
const useDepthBuffer = const useDepthBuffer =
!failedFBO && (this.settings.browser.graphicsQuality === GraphicsQuality.High) && !!frameBuffer!.depthStencilRenderbuffer; !failedFBO && (this.settings.browser.graphicsQuality === GraphicsQuality.High) && !!frameBuffer!.depthStencilRenderbuffer;
@@ -1342,12 +1409,16 @@ export class PonyTownGame implements Game {
gl.depthFunc(gl.ALWAYS); gl.depthFunc(gl.ALWAYS);
if (drawSceneDirectlyOntoScreen) { if (drawSceneDirectlyOntoScreen) {
TIMING && timeStart('color -> screen'); if (TIMING) {
timeStart('color -> screen');
}
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
this.drawMap(this.webgl, this.map, this.viewMatrix, mapDrawingColor, drawOptions); this.drawMap(this.webgl, this.map, this.viewMatrix, mapDrawingColor, drawOptions);
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
} }
else { else {
// if (!isWebGL2(gl)) { // if (!isWebGL2(gl)) {
@@ -1361,17 +1432,23 @@ export class PonyTownGame implements Game {
clearMask |= gl.DEPTH_BUFFER_BIT; clearMask |= gl.DEPTH_BUFFER_BIT;
} }
TIMING && timeStart('color -> framebuffer'); if (TIMING) {
timeStart('color -> framebuffer');
}
bindFrameBuffer(gl, frameBuffer!); bindFrameBuffer(gl, frameBuffer!);
gl.viewport(0, 0, frameBuffer!.width, frameBuffer!.height); // clearing the whole surface is preferable for most GPUs gl.viewport(0, 0, frameBuffer!.width, frameBuffer!.height); // clearing the whole surface is preferable for most GPUs
gl.clear(clearMask); gl.clear(clearMask);
gl.viewport(0, 0, width, height); gl.viewport(0, 0, width, height);
this.drawMap(this.webgl, this.map, this.viewMatrix, mapDrawingColor, drawOptions); this.drawMap(this.webgl, this.map, this.viewMatrix, mapDrawingColor, drawOptions);
gl.depthMask(false); gl.depthMask(false);
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
if (useLighting) { if (useLighting) {
TIMING && timeStart('light -> fbo'); if (TIMING) {
timeStart('light -> fbo');
}
bindFrameBuffer(gl, frameBuffer2!); bindFrameBuffer(gl, frameBuffer2!);
gl.viewport(0, 0, frameBuffer2!.width, frameBuffer2!.height); // clearing the whole surface is preferable for most GPUs gl.viewport(0, 0, frameBuffer2!.width, frameBuffer2!.height); // clearing the whole surface is preferable for most GPUs
gl.clearColor(light[0], light[1], light[2], light[3]); gl.clearColor(light[0], light[1], light[2], light[3]);
@@ -1402,9 +1479,13 @@ export class PonyTownGame implements Game {
if (isWebGL2(gl)) { if (isWebGL2(gl)) {
(gl as WebGL2RenderingContext).invalidateFramebuffer(gl.FRAMEBUFFER, [gl.DEPTH_ATTACHMENT]); (gl as WebGL2RenderingContext).invalidateFramebuffer(gl.FRAMEBUFFER, [gl.DEPTH_ATTACHMENT]);
} }
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
TIMING && timeStart('color + lights -> screen'); if (TIMING) {
timeStart('color + lights -> screen');
}
unbindFrameBuffer(gl); unbindFrameBuffer(gl);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.disable(gl.BLEND); gl.disable(gl.BLEND);
@@ -1417,10 +1498,14 @@ export class PonyTownGame implements Game {
spriteBatch.begin(); spriteBatch.begin();
spriteBatch.drawImage(WHITE, 0, 0, width, height, 0, 0, width, height); spriteBatch.drawImage(WHITE, 0, 0, width, height, 0, 0, width, height);
spriteBatch.end(); spriteBatch.end();
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
} }
else { else {
TIMING && timeStart('color framebuffer -> screen'); if (TIMING) {
timeStart('color framebuffer -> screen');
}
unbindFrameBuffer(gl); unbindFrameBuffer(gl);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.disable(gl.BLEND); gl.disable(gl.BLEND);
@@ -1433,7 +1518,9 @@ export class PonyTownGame implements Game {
spriteBatch.begin(); spriteBatch.begin();
spriteBatch.drawImage(WHITE, 0, 0, width, height, 0, 0, width, height); spriteBatch.drawImage(WHITE, 0, 0, width, height, 0, 0, width, height);
spriteBatch.end(); spriteBatch.end();
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
} }
} }
@@ -1442,7 +1529,9 @@ export class PonyTownGame implements Game {
gl.blendEquation(gl.FUNC_ADD); gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
TIMING && timeStart('drawNames+drawChat'); if (TIMING) {
timeStart('drawNames+drawChat');
}
gl.useProgram(paletteShader.program); gl.useProgram(paletteShader.program);
gl.uniformMatrix4fv(paletteShader.uniforms.transform, false, this.fboMatrix); gl.uniformMatrix4fv(paletteShader.uniforms.transform, false, this.fboMatrix);
gl.uniform4fv(paletteShader.uniforms.lighting, white); gl.uniform4fv(paletteShader.uniforms.lighting, white);
@@ -1461,13 +1550,16 @@ export class PonyTownGame implements Game {
if (!this.socket || !this.socket.isConnected) { if (!this.socket || !this.socket.isConnected) {
this.drawMessage(this.webgl, 'Connecting...'); this.drawMessage(this.webgl, 'Connecting...');
} else if (!this.loaded) { }
else if (!this.loaded) {
if (this.placeInQueue) { if (this.placeInQueue) {
this.drawMessage(this.webgl, `Waiting in queue (${this.placeInQueue})`); this.drawMessage(this.webgl, `Waiting in queue (${this.placeInQueue})`);
} else { }
else {
this.drawMessage(this.webgl, 'Loading...'); this.drawMessage(this.webgl, 'Loading...');
} }
} else if ((performance.now() - this.socket.lastPacket) > CONNECTION_ISSUE_TIMEOUT) { }
else if ((performance.now() - this.socket.lastPacket) > CONNECTION_ISSUE_TIMEOUT) {
// this.drawMessage('Connection issues...'); // this.drawMessage('Connection issues...');
} }
@@ -1478,7 +1570,8 @@ export class PonyTownGame implements Game {
const y = this.input.pointerY / scale; const y = this.input.pointerY / scale;
const height = getMapHeightAt(this.map, this.hover.x, this.hover.y, this.time); const height = getMapHeightAt(this.map, this.hover.x, this.hover.y, this.time);
drawText(paletteBatch, `${height.toFixed(2)}`, fontSmallPal, BLACK, x, y); drawText(paletteBatch, `${height.toFixed(2)}`, fontSmallPal, BLACK, x, y);
} catch (e) { }
catch (e) {
console.warn(e); console.warn(e);
} }
} }
@@ -1497,13 +1590,16 @@ export class PonyTownGame implements Game {
if (dx > dy) { if (dx > dy) {
if ((dx + dy) < 1) { if ((dx + dy) < 1) {
paletteBatch.drawSprite(wall_h_placeholder.color, color, palette, screenX, screenY - 15); paletteBatch.drawSprite(wall_h_placeholder.color, color, palette, screenX, screenY - 15);
} else { }
else {
paletteBatch.drawSprite(wall_v_placeholder.color, color, palette, screenX + tileWidth - 4, screenY - 12); paletteBatch.drawSprite(wall_v_placeholder.color, color, palette, screenX + tileWidth - 4, screenY - 12);
} }
} else { }
else {
if ((dx + dy) < 1) { if ((dx + dy) < 1) {
paletteBatch.drawSprite(wall_v_placeholder.color, color, palette, screenX - 4, screenY - 12); paletteBatch.drawSprite(wall_v_placeholder.color, color, palette, screenX - 4, screenY - 12);
} else { }
else {
paletteBatch.drawSprite(wall_h_placeholder.color, color, palette, screenX, screenY + tileHeight - 15); paletteBatch.drawSprite(wall_h_placeholder.color, color, palette, screenX, screenY + tileHeight - 15);
} }
} }
@@ -1511,7 +1607,9 @@ export class PonyTownGame implements Game {
} }
paletteBatch.end(); paletteBatch.end();
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
gl.useProgram(spriteShaderWithColor.program); gl.useProgram(spriteShaderWithColor.program);
gl.uniformMatrix4fv(spriteShaderWithColor.uniforms.transform, false, this.fboMatrix); gl.uniformMatrix4fv(spriteShaderWithColor.uniforms.transform, false, this.fboMatrix);
@@ -1562,7 +1660,9 @@ export class PonyTownGame implements Game {
if (showFPS || showHelp || showPalette || showAdditionalStats) { if (showFPS || showHelp || showPalette || showAdditionalStats) {
// 1 to 1 pixel scale drawing // 1 to 1 pixel scale drawing
TIMING && timeStart('showFps'); if (TIMING) {
timeStart('showFps');
}
const scale = 2; const scale = 2;
ortho(this.fboMatrix, 0, gl.drawingBufferWidth / ratio, gl.drawingBufferHeight / ratio, 0, 0, 1000, false); ortho(this.fboMatrix, 0, gl.drawingBufferWidth / ratio, gl.drawingBufferHeight / ratio, 0, 0, 1000, false);
gl.uniformMatrix4fv(spriteShaderWithColor.uniforms.transform, false, this.fboMatrix); gl.uniformMatrix4fv(spriteShaderWithColor.uniforms.transform, false, this.fboMatrix);
@@ -1626,25 +1726,37 @@ export class PonyTownGame implements Game {
spriteBatch.end(); spriteBatch.end();
} }
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
} }
bindTexture(gl, 0, undefined); bindTexture(gl, 0, undefined);
bindTexture(gl, 1, undefined); bindTexture(gl, 1, undefined);
gl.useProgram(null); gl.useProgram(null);
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
this.updateStatsText(); this.updateStatsText();
TIMING && timeStart('messageQueue'); if (TIMING) {
timeStart('messageQueue');
}
while (this.messageQueue.length) { while (this.messageQueue.length) {
this.onMessage.next(this.messageQueue.shift()!); this.onMessage.next(this.messageQueue.shift()!);
} }
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
TIMING && timeStart('onFrame'); if (TIMING) {
timeStart('onFrame');
}
this.onFrame.next(); this.onFrame.next();
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
} }
private drawMessage({ paletteBatch, palettes }: WebGL, message: string) { private drawMessage({ paletteBatch, palettes }: WebGL, message: string) {
drawFullScreenMessage(paletteBatch, this.camera, message, palettes.mainFont.white); drawFullScreenMessage(paletteBatch, this.camera, message, palettes.mainFont.white);
@@ -1654,7 +1766,9 @@ export class PonyTownGame implements Game {
const mapPaletteShader = options.useDepthBuffer ? paletteShaderWithDepth : paletteShader; const mapPaletteShader = options.useDepthBuffer ? paletteShaderWithDepth : paletteShader;
TIMING && timeStart('drawMap'); if (TIMING) {
timeStart('drawMap');
}
if (this.tileSets && this.player) { if (this.tileSets && this.player) {
gl.useProgram(mapPaletteShader.program); gl.useProgram(mapPaletteShader.program);
gl.uniformMatrix4fv(mapPaletteShader.uniforms.transform, false, viewMatrix); gl.uniformMatrix4fv(mapPaletteShader.uniforms.transform, false, viewMatrix);
@@ -1675,14 +1789,18 @@ export class PonyTownGame implements Game {
paletteBatch.end(); paletteBatch.end();
} }
} }
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
} }
private updateCameraShift() { private updateCameraShift() {
if (isMobile) { if (isMobile) {
const isKeyboardOpen = !!document.activeElement && /input/i.test(document.activeElement.tagName); const isKeyboardOpen = !!document.activeElement && /input/i.test(document.activeElement.tagName);
if (this.lastIsKeyboardOpen !== isKeyboardOpen) { if (this.lastIsKeyboardOpen !== isKeyboardOpen) {
DEVELOPMENT && log(`keyboard open ${isKeyboardOpen}`); if (DEVELOPMENT) {
log(`keyboard open ${isKeyboardOpen}`);
}
this.lastIsKeyboardOpen = isKeyboardOpen; this.lastIsKeyboardOpen = isKeyboardOpen;
} }
@@ -1695,10 +1813,13 @@ export class PonyTownGame implements Game {
log(`shift camera ${this.cameraShiftTarget} (${this.windowHeight} - ${window.innerHeight}, ${window.scrollY})`); log(`shift camera ${this.cameraShiftTarget} (${this.windowHeight} - ${window.innerHeight}, ${window.scrollY})`);
} }
} }
} else { }
else {
if (this.cameraShiftOn && window.scrollY < 100) { if (this.cameraShiftOn && window.scrollY < 100) {
this.cameraShiftOn = false; this.cameraShiftOn = false;
DEVELOPMENT && log(`unshift camera`); if (DEVELOPMENT) {
log(`unshift camera`);
}
} }
} }
} }
@@ -1728,7 +1849,9 @@ export class PonyTownGame implements Game {
canvas.style.height = `${h / ratio}px`; canvas.style.height = `${h / ratio}px`;
this.lastCanvasRatio = ratio; this.lastCanvasRatio = ratio;
this.resized = false; this.resized = false;
DEVELOPMENT && log(`scrollY: ${window.scrollY}`); if (DEVELOPMENT) {
log(`scrollY: ${window.scrollY}`);
}
} }
} }
private initializeFrameBuffers( private initializeFrameBuffers(
@@ -1748,8 +1871,11 @@ export class PonyTownGame implements Game {
if (isSizeTooBig) { if (isSizeTooBig) {
this.setScale(this.scale + 1); // should not happen, useDepthBuffer is also ignored if it does this.setScale(this.scale + 1); // should not happen, useDepthBuffer is also ignored if it does
DEVELOPMENT && console.warn('Cannot resize framebuffer'); if (DEVELOPMENT) {
} else { console.warn('Cannot resize framebuffer');
}
}
else {
disposeFrameBuffer(gl, frameBuffer); disposeFrameBuffer(gl, frameBuffer);
disposeFrameBuffer(gl, frameBuffer2); disposeFrameBuffer(gl, frameBuffer2);
createFrameBuffer(gl, frameBuffer, width, height, useDepthBuffer, null); createFrameBuffer(gl, frameBuffer, width, height, useDepthBuffer, null);
@@ -1763,7 +1889,8 @@ export class PonyTownGame implements Game {
changePlaceEntity(reverse: boolean) { changePlaceEntity(reverse: boolean) {
if (reverse) { if (reverse) {
this.placeEntity = this.placeEntity === 0 ? (placeableEntities.length - 1) : (this.placeEntity - 1); this.placeEntity = this.placeEntity === 0 ? (placeableEntities.length - 1) : (this.placeEntity - 1);
} else { }
else {
this.placeEntity = (this.placeEntity + 1) % placeableEntities.length; this.placeEntity = (this.placeEntity + 1) % placeableEntities.length;
} }
@@ -1774,7 +1901,8 @@ export class PonyTownGame implements Game {
changePlaceTile(reverse: boolean) { changePlaceTile(reverse: boolean) {
if (reverse) { if (reverse) {
this.placeTile = this.placeTile === 0 ? (houseTiles.length - 1) : (this.placeTile - 1); this.placeTile = this.placeTile === 0 ? (houseTiles.length - 1) : (this.placeTile - 1);
} else { }
else {
this.placeTile = (this.placeTile + 1) % houseTiles.length; this.placeTile = (this.placeTile + 1) % houseTiles.length;
} }
@@ -1789,7 +1917,9 @@ export class PonyTownGame implements Game {
const { gl, spriteBatch, paletteBatch } = this.webgl!; const { gl, spriteBatch, paletteBatch } = this.webgl!;
if ((performance.now() - this.lastStats) > SECOND) { if ((performance.now() - this.lastStats) > SECOND) {
TIMING && timingCollate(); if (TIMING) {
timingCollate();
}
if (TIMING) { if (TIMING) {
const timings = timingCollate(); const timings = timingCollate();
@@ -1834,7 +1964,9 @@ export class PonyTownGame implements Game {
this.onClock.next(formatHourMinutes(this.time)); this.onClock.next(formatHourMinutes(this.time));
} }
TIMING && timeReset(); if (TIMING) {
timeReset();
}
spriteBatch!.drawnTrisStats = 0; spriteBatch!.drawnTrisStats = 0;
spriteBatch!.flushes = 0; spriteBatch!.flushes = 0;
+4 -2
View File
@@ -45,7 +45,8 @@ export function startGameLoop(game: Game, onError = (e: Error) => console.error(
if (draw) { if (draw) {
game.draw(); game.draw();
} }
} catch (e) { }
catch (e) {
if (isError(e)) { if (isError(e)) {
onError(e); onError(e);
} }
@@ -80,7 +81,8 @@ export function startGameLoop(game: Game, onError = (e: Error) => console.error(
.then(() => { .then(() => {
if (cancelled) { if (cancelled) {
throw new Error('Cancelled (loop)'); throw new Error('Cancelled (loop)');
} else { }
else {
game.init(); game.init();
handle = requestAnimationFrame(onFrame); handle = requestAnimationFrame(onFrame);
backup = setTimeout(onTimer, 1000 / 10); backup = setTimeout(onTimer, 1000 / 10);
+73 -35
View File
@@ -130,7 +130,8 @@ export function handleUpdateEntity(game: PonyTownGame, update: DecodedUpdate) {
} }
} }
} }
} else if (distanceXY(entity.x, entity.y, x, y) > 8) { }
else if (distanceXY(entity.x, entity.y, x, y) > 8) {
log(`Fixing player position (${entity.x}, ${entity.y}) => (${x}, ${y})`); log(`Fixing player position (${entity.x}, ${entity.y}) => (${x}, ${y})`);
entity.x = x; entity.x = x;
entity.y = y; entity.y = y;
@@ -163,7 +164,8 @@ export function handleUpdateEntity(game: PonyTownGame, update: DecodedUpdate) {
if (entity.fake) { if (entity.fake) {
(entity as Pony).palettePonyInfo = decodePonyInfo(ponyInfo, mockPaletteManager); (entity as Pony).palettePonyInfo = decodePonyInfo(ponyInfo, mockPaletteManager);
} else { }
else {
updatePonyInfoWithPoof(game, entity, ponyInfo, crc); updatePonyInfoWithPoof(game, entity, ponyInfo, crc);
} }
} }
@@ -173,7 +175,8 @@ export function handleUpdateEntity(game: PonyTownGame, update: DecodedUpdate) {
} }
applyIfSelected(game, id); applyIfSelected(game, id);
} else { }
else {
log(`handleUpdateEntity: missing entity: ${id}`); log(`handleUpdateEntity: missing entity: ${id}`);
} }
} }
@@ -315,7 +318,8 @@ export function handleUpdates(game: PonyTownGame, updates: Uint8Array) {
if (region) { if (region) {
handleAddEntity(game, region, update, false); handleAddEntity(game, region, update, false);
} else { }
else {
log(`handleUpdates (add): missing region at ${x} ${y}`); log(`handleUpdates (add): missing region at ${x} ${y}`);
} }
break; break;
@@ -353,7 +357,8 @@ export function updatePonyInfoWithPoof(game: PonyTownGame, entity: Entity, info:
if (entity && isPony(entity)) { if (entity && isPony(entity)) {
if (isHidden(entity)) { if (isHidden(entity)) {
update(entity); update(entity);
} else { }
else {
playEffect(game, entity, poof2.type); playEffect(game, entity, poof2.type);
setTimeout(() => update(entity), 100); setTimeout(() => update(entity), 100);
} }
@@ -365,7 +370,8 @@ export function handleRemoveEntity(game: PonyTownGame, id: number) {
if (entity) { if (entity) {
removeEntity(game.map, entity); removeEntity(game.map, entity);
} else { }
else {
log(`handleRemoveEntity: Missing entity: ${id}`); log(`handleRemoveEntity: Missing entity: ${id}`);
} }
@@ -441,21 +447,26 @@ export function handleAction(game: PonyTownGame, id: number, action: Action) {
default: default:
log(`handleAction: Invalid action: ${action}`); log(`handleAction: Invalid action: ${action}`);
} }
} else { }
else {
log(`handleAction: Missing entity: ${id}`); log(`handleAction: Missing entity: ${id}`);
} }
} }
export function playEffect(game: PonyTownGame, target: Entity, type: number) { export function playEffect(game: PonyTownGame, target: Entity, type: number) {
if (isHidden(target)) if (isHidden(target)) {
return; return;
}
try { try {
const entity = createAnEntity(type, 0, target.x, target.y, {}, game.paletteManager, game); const entity = createAnEntity(type, 0, target.x, target.y, {}, game.paletteManager, game);
addEntity(game.map, entity); addEntity(game.map, entity);
setTimeout(() => removeEntityDirectly(game.map, entity), 1000); setTimeout(() => removeEntityDirectly(game.map, entity), 1000);
} catch (e) { }
DEVELOPMENT && console.error(e); catch (e) {
if (DEVELOPMENT) {
console.error(e);
}
} }
} }
@@ -554,7 +565,8 @@ export function containsFilteredWords(message: string, filter: string | undefine
if (filter) { if (filter) {
const words = compact(filter.replace(/[,]/g, ' ').split(/[\r\n\t ]+/g).map(x => x.trim())); const words = compact(filter.replace(/[,]/g, ' ').split(/[\r\n\t ]+/g).map(x => x.trim()));
cachedRegex = new RegExp(`(^| )(${words.map(escapeRegExp).join('|')})($| )`, 'i'); cachedRegex = new RegExp(`(^| )(${words.map(escapeRegExp).join('|')})($| )`, 'i');
} else { }
else {
cachedRegex = undefined; cachedRegex = undefined;
} }
@@ -569,8 +581,11 @@ export function handleSays(game: PonyTownGame, id: number, message: string, type
if (entity) { if (entity) {
handleSay(game, entity, message, type); handleSay(game, entity, message, type);
} else { }
DEVELOPMENT && console.warn('incomplete say'); else {
if (DEVELOPMENT) {
console.warn('incomplete say');
}
game.incompleteSays.push({ id, message, type, time: Date.now() }); game.incompleteSays.push({ id, message, type, time: Date.now() });
game.send(server => server.actionParam2(Action.RequestEntityInfo, id)); game.send(server => server.actionParam2(Action.RequestEntityInfo, id));
} }
@@ -589,32 +604,41 @@ function isFriendEntityId(game: PonyTownGame, id: number) {
} }
function shouldShowChatMessage(game: PonyTownGame, entity: Entity | FakeEntity, message: string, type: MessageType): boolean { function shouldShowChatMessage(game: PonyTownGame, entity: Entity | FakeEntity, message: string, type: MessageType): boolean {
if (entity === game.player) if (entity === game.player) {
return true; return true;
}
if (isWhisperTo(type)) if (isWhisperTo(type)) {
return true; return true;
}
if (isWhisper(type) && isFriendEntityId(game, entity.id)) if (isWhisper(type) && isFriendEntityId(game, entity.id)) {
return true; return true;
}
if (isPublicMessage(type) && !entity.fake && !isChatVisible(game.camera, entity)) if (isPublicMessage(type) && !entity.fake && !isChatVisible(game.camera, entity)) {
return false; return false;
}
if (isNonIgnorableMessage(type)) if (isNonIgnorableMessage(type)) {
return true; return true;
}
if (game.settings.account.filterCyrillic && containsCyrillic(message)) if (game.settings.account.filterCyrillic && containsCyrillic(message)) {
return false; return false;
}
if (game.settings.account.ignorePublicChat && isPublicMessage(type)) if (game.settings.account.ignorePublicChat && isPublicMessage(type)) {
return false; return false;
}
if (isWhisper(type) && game.settings.account.ignoreNonFriendWhispers) if (isWhisper(type) && game.settings.account.ignoreNonFriendWhispers) {
return false; return false;
}
if (containsFilteredWords(message, game.settings.account.filterWords)) if (containsFilteredWords(message, game.settings.account.filterWords)) {
return false; return false;
}
return true; return true;
} }
@@ -624,30 +648,36 @@ function isChatInRange(entity: Entity, player: Entity | undefined, range: number
} }
function shouldShowChatMessageInChatlog(game: PonyTownGame, entity: Entity | FakeEntity, type: MessageType) { function shouldShowChatMessageInChatlog(game: PonyTownGame, entity: Entity | FakeEntity, type: MessageType) {
if (entity.type !== PONY_TYPE) if (entity.type !== PONY_TYPE) {
return false; return false;
}
if (entity.fake) if (entity.fake) {
return true; return true;
}
if (!isPublicMessage(type)) if (!isPublicMessage(type)) {
return true; return true;
}
if (!isChatInRange(entity, game.player, game.settings.account.chatlogRange)) if (!isChatInRange(entity, game.player, game.settings.account.chatlogRange)) {
return false; return false;
}
return true; return true;
} }
export function handleSay(game: PonyTownGame, entity: Entity | FakeEntity, message: string, type: MessageType) { export function handleSay(game: PonyTownGame, entity: Entity | FakeEntity, message: string, type: MessageType) {
if (!shouldShowChatMessage(game, entity, message, type)) if (!shouldShowChatMessage(game, entity, message, type)) {
return; return;
}
if (type === MessageType.Dismiss || message === '.') { if (type === MessageType.Dismiss || message === '.') {
if (!entity.fake && entity.says) { if (!entity.fake && entity.says) {
dismissSays(entity.says); dismissSays(entity.says);
} }
} else { }
else {
const bubbleEntity = isWhisperTo(type) ? game.player : entity; const bubbleEntity = isWhisperTo(type) ? game.player : entity;
if (bubbleEntity && !bubbleEntity.fake && game.map.entitiesById.has(bubbleEntity.id)) { if (bubbleEntity && !bubbleEntity.fake && game.map.entitiesById.has(bubbleEntity.id)) {
@@ -677,7 +707,8 @@ export function handleEntityInfo(game: PonyTownGame, id: number, name: string, c
game.incompleteSays.splice(i, 1); game.incompleteSays.splice(i, 1);
const entity: FakeEntity = { fake: true, type: PONY_TYPE, id, name, crc }; const entity: FakeEntity = { fake: true, type: PONY_TYPE, id, name, crc };
handleSay(game, entity, say.message, say.type); handleSay(game, entity, say.message, say.type);
} else { }
else {
i++; i++;
} }
} }
@@ -697,9 +728,11 @@ export function subscribeRegion(game: PonyTownGame, data: Uint8Array) {
export function filterEntityName({ settings, worldFlags }: PonyTownGame, name: string | undefined, nameBad: boolean) { export function filterEntityName({ settings, worldFlags }: PonyTownGame, name: string | undefined, nameBad: boolean) {
if (name && nameBad && (settings.account.filterSwearWords || hasFlag(worldFlags, WorldStateFlags.Safe))) { if (name && nameBad && (settings.account.filterSwearWords || hasFlag(worldFlags, WorldStateFlags.Safe))) {
return repeat('*', name.length); return repeat('*', name.length);
} else if (name && containsFilteredWords(name, settings.account.filterWords)) { }
else if (name && containsFilteredWords(name, settings.account.filterWords)) {
return repeat('?', name.length); return repeat('?', name.length);
} else { }
else {
return name; return name;
} }
} }
@@ -722,7 +755,8 @@ function createEntityOrPony(
} }
return entity; return entity;
} else { }
else {
const entity = createAnEntity(type, id, x, y, options, game.paletteManager, game); const entity = createAnEntity(type, id, x, y, options, game.paletteManager, game);
entity.state = state; entity.state = state;
@@ -744,8 +778,9 @@ function updateEntityOptionsInternal(entity: Entity, options: Partial<EntityOrPo
} }
export function handleUpdateFriends(game: PonyTownGame, friends: FriendStatusData[], removeMissing: boolean) { export function handleUpdateFriends(game: PonyTownGame, friends: FriendStatusData[], removeMissing: boolean) {
if (!game.model.friends) if (!game.model.friends) {
return; return;
}
for (const { accountId, accountName, status, entityId, name, info, crc, nameBad = false } of friends) { for (const { accountId, accountName, status, entityId, name, info, crc, nameBad = false } of friends) {
let friend = game.model.friends.find(f => f.accountId === accountId); let friend = game.model.friends.find(f => f.accountId === accountId);
@@ -754,7 +789,8 @@ export function handleUpdateFriends(game: PonyTownGame, friends: FriendStatusDat
if (friend) { if (friend) {
removeItem(game.model.friends, friend); removeItem(game.model.friends, friend);
} }
} else { }
else {
if (!friend) { if (!friend) {
friend = { friend = {
accountId, accountId,
@@ -817,7 +853,9 @@ export function handleUpdateFriends(game: PonyTownGame, friends: FriendStatusDat
} }
} }
DEVELOPMENT && console.log('Refreshing friend list'); if (DEVELOPMENT) {
console.log('Refreshing friend list');
}
} }
game.model.friends.sort(compareFriends); game.model.friends.sort(compareFriends);
+7 -3
View File
@@ -27,7 +27,8 @@ export function createHtmlNodes(value: string | undefined, scale: number): Node[
}); });
return img; return img;
} else { }
else {
return document.createTextNode(x); return document.createTextNode(x);
} }
}) : []; }) : [];
@@ -88,7 +89,9 @@ export function removeFirstChild(element: HTMLElement) {
} }
export function removeElement(element: HTMLElement) { export function removeElement(element: HTMLElement) {
element.parentElement && element.parentElement.removeChild(element); if (element.parentElement) {
element.parentElement.removeChild(element);
}
} }
export function replaceNodes(element: HTMLElement, text: string) { export function replaceNodes(element: HTMLElement, text: string) {
@@ -105,7 +108,8 @@ export function replaceNodes(element: HTMLElement, text: string) {
if (hasEmojis(text)) { if (hasEmojis(text)) {
firstChild.nodeValue = ''; firstChild.nodeValue = '';
appendAllNodes(element, createHtmlNodes(text, 2)); appendAllNodes(element, createHtmlNodes(text, 2));
} else { }
else {
firstChild.nodeValue = text; firstChild.nodeValue = text;
} }
} }
+6 -3
View File
@@ -55,7 +55,8 @@ function button({ mapping, gamepad }: GamepadInstance, name: GamepadButtons) {
if (button.axis !== undefined) { if (button.axis !== undefined) {
if (button.direction < 0) { if (button.direction < 0) {
return gamepad.axes[button.axis] < -0.75; return gamepad.axes[button.axis] < -0.75;
} else { }
else {
return gamepad.axes[button.axis] > 0.75; return gamepad.axes[button.axis] > 0.75;
} }
} }
@@ -84,8 +85,9 @@ export class GamePadController implements InputController {
window.removeEventListener('gamepaddisconnected', this.gamepaddisconnected); window.removeEventListener('gamepaddisconnected', this.gamepaddisconnected);
} }
update() { update() {
if (this.manager.disabledGamepad || !isFocused() || this.gamepadIndex === -1) if (this.manager.disabledGamepad || !isFocused() || this.gamepadIndex === -1) {
return; return;
}
const gamepads = navigator.getGamepads(); const gamepads = navigator.getGamepads();
const gamepad = gamepads[this.gamepadIndex]; const gamepad = gamepads[this.gamepadIndex];
@@ -150,7 +152,8 @@ function readAxis(manager: InputManager, keyX: Key, keyY: Key, axisX: number, ax
manager.setValue(keyX, Math.cos(theta) * scaledDist); manager.setValue(keyX, Math.cos(theta) * scaledDist);
manager.setValue(keyY, Math.sin(theta) * scaledDist); manager.setValue(keyY, Math.sin(theta) * scaledDist);
return false; return false;
} else if (!zeroed) { }
else if (!zeroed) {
manager.setValue(keyX, 0); manager.setValue(keyX, 0);
manager.setValue(keyY, 0); manager.setValue(keyY, 0);
return true; return true;
+4 -2
View File
@@ -146,7 +146,8 @@ export class InputManager {
setValue(input: Key, value: number): boolean { setValue(input: Key, value: number): boolean {
if (input < 0 || input >= KEYS) { if (input < 0 || input >= KEYS) {
console.warn(`Input out of range: ${input}`); console.warn(`Input out of range: ${input}`);
} else if (this.state[input] !== value) { }
else if (this.state[input] !== value) {
this.state[input] = value; this.state[input] = value;
if (this.actions[input] && this.actions[input].length) { if (this.actions[input] && this.actions[input].length) {
@@ -163,7 +164,8 @@ export class InputManager {
addValue(input: Key, value: number) { addValue(input: Key, value: number) {
if (input < 0 || input >= KEYS) { if (input < 0 || input >= KEYS) {
console.warn(`Input out of range: ${input}`); console.warn(`Input out of range: ${input}`);
} else { }
else {
this.state[input] += value; this.state[input] += value;
} }
} }
+6 -2
View File
@@ -14,8 +14,12 @@ function allowKey(key: number) {
function fixKeyCode(key: number) { function fixKeyCode(key: number) {
if (firefox) { if (firefox) {
if (key === 173) return Key.DASH; if (key === 173) {
if (key === 61) return Key.EQUALS; return Key.DASH;
}
if (key === 61) {
return Key.EQUALS;
}
} }
return key; return key;
+7 -3
View File
@@ -122,13 +122,16 @@ export class TouchController implements InputController {
this.touchIsDrag = true; this.touchIsDrag = true;
this.manager.setValue(Key.GAMEPAD_AXIS1_X, -Math.cos(theta) * scaledDist); this.manager.setValue(Key.GAMEPAD_AXIS1_X, -Math.cos(theta) * scaledDist);
this.manager.setValue(Key.GAMEPAD_AXIS1_Y, -Math.sin(theta) * scaledDist); this.manager.setValue(Key.GAMEPAD_AXIS1_Y, -Math.sin(theta) * scaledDist);
} else { }
else {
this.manager.setValue(Key.GAMEPAD_AXIS1_X, 0); this.manager.setValue(Key.GAMEPAD_AXIS1_X, 0);
this.manager.setValue(Key.GAMEPAD_AXIS1_Y, 0); this.manager.setValue(Key.GAMEPAD_AXIS1_Y, 0);
} }
} }
private touchstart = (e: any) => { private touchstart = (e: any) => {
e.cancellable && e.preventDefault(); if (e.cancellable) {
e.preventDefault();
}
e.stopPropagation(); e.stopPropagation();
this.manager.usingTouch = true; this.manager.usingTouch = true;
@@ -144,7 +147,8 @@ export class TouchController implements InputController {
this.manager.setValue(Key.MOUSE_Y, this.touchStart.y); this.manager.setValue(Key.MOUSE_Y, this.touchStart.y);
this.manager.setValue(Key.TOUCH, 1); this.manager.setValue(Key.TOUCH, 1);
} }
} else if (this.touch2Id === -1) { }
else if (this.touch2Id === -1) {
const touch = e.changedTouches.item(0); const touch = e.changedTouches.item(0);
if (touch) { if (touch) {
+4 -2
View File
@@ -5,7 +5,8 @@ import { PonyTownGame } from './game';
export function updateParty(current: PartyInfo | undefined, info: PartyMember[] | undefined): PartyInfo | undefined { export function updateParty(current: PartyInfo | undefined, info: PartyMember[] | undefined): PartyInfo | undefined {
if (!info || !info.length) { if (!info || !info.length) {
return undefined; return undefined;
} else { }
else {
const party = current || { const party = current || {
leaderId: 0, leaderId: 0,
members: [], members: [],
@@ -18,7 +19,8 @@ export function updateParty(current: PartyInfo | undefined, info: PartyMember[]
if (existing) { if (existing) {
Object.assign(existing, m); Object.assign(existing, m);
} else { }
else {
party.members.push(m); party.members.push(m);
} }
+33 -16
View File
@@ -37,7 +37,8 @@ export function handleActionCommand(message: string, game: PonyTownGame): boolea
if (player) { if (player) {
if (isPonyLying(player)) { if (isPonyLying(player)) {
sitAction(player, game); sitAction(player, game);
} else { }
else {
lieAction(player, game); lieAction(player, game);
} }
} }
@@ -46,7 +47,8 @@ export function handleActionCommand(message: string, game: PonyTownGame): boolea
if (player) { if (player) {
if (isPonyFlying(player)) { if (isPonyFlying(player)) {
standAction(player, game); standAction(player, game);
} else { }
else {
sitAction(player, game); sitAction(player, game);
} }
} }
@@ -60,7 +62,8 @@ export function handleActionCommand(message: string, game: PonyTownGame): boolea
if (player) { if (player) {
if (isPonyFlying(player)) { if (isPonyFlying(player)) {
standAction(player, game); standAction(player, game);
} else { }
else {
flyAction(player, game); flyAction(player, game);
} }
} }
@@ -77,9 +80,11 @@ export function upAction(game: PonyTownGame) {
if (player) { if (player) {
if (isPonyLying(player)) { if (isPonyLying(player)) {
sitAction(player, game); sitAction(player, game);
} else if (isPonySitting(player)) { }
else if (isPonySitting(player)) {
standAction(player, game); standAction(player, game);
} else if (isPonyStanding(player)) { }
else if (isPonyStanding(player)) {
flyAction(player, game); flyAction(player, game);
} }
} }
@@ -91,9 +96,11 @@ export function downAction(game: PonyTownGame) {
if (player) { if (player) {
if (isPonySitting(player)) { if (isPonySitting(player)) {
lieAction(player, game); lieAction(player, game);
} else if (isPonyStanding(player)) { }
else if (isPonyStanding(player)) {
sitAction(player, game); sitAction(player, game);
} else if (isPonyFlying(player)) { }
else if (isPonyFlying(player)) {
standAction(player, game); standAction(player, game);
} }
} }
@@ -172,11 +179,14 @@ export function interact(game: PonyTownGame, shift: boolean) {
if (entity && entityInRange(entity, player)) { if (entity && entityInRange(entity, player)) {
game.send(server => server.interact(entity.id)); game.send(server => server.interact(entity.id));
} else if (player.hold === hammer.type) { }
else if (player.hold === hammer.type) {
game.changePlaceEntity(shift); game.changePlaceEntity(shift);
} else if (player.hold === shovel.type) { }
else if (player.hold === shovel.type) {
game.changePlaceTile(shift); game.changePlaceTile(shift);
} else if (player.ponyState.holding && hasFlag(player.ponyState.holding.flags, EntityFlags.Usable)) { }
else if (player.ponyState.holding && hasFlag(player.ponyState.holding.flags, EntityFlags.Usable)) {
game.send(server => server.use()); game.send(server => server.use());
} }
} }
@@ -191,13 +201,16 @@ export function toggleWall(game: PonyTownGame, hover: Point) {
if (dx > dy) { if (dx > dy) {
if ((dx + dy) < 1) { if ((dx + dy) < 1) {
game.send(server => server.changeTile(x, y, TileType.WallH)); game.send(server => server.changeTile(x, y, TileType.WallH));
} else { }
else {
game.send(server => server.changeTile(x + 1, y, TileType.WallV)); game.send(server => server.changeTile(x + 1, y, TileType.WallV));
} }
} else { }
else {
if ((dx + dy) < 1) { if ((dx + dy) < 1) {
game.send(server => server.changeTile(x, y, TileType.WallV)); game.send(server => server.changeTile(x, y, TileType.WallV));
} else { }
else {
game.send(server => server.changeTile(x, y + 1, TileType.WallH)); game.send(server => server.changeTile(x, y + 1, TileType.WallH));
} }
} }
@@ -209,8 +222,11 @@ export function editorSelectEntities(game: PonyTownGame, hover: Point, shift: bo
if (shift) { if (shift) {
const entity = entities.filter(e => !includes(game.editor.selectedEntities, e))[0]; const entity = entities.filter(e => !includes(game.editor.selectedEntities, e))[0];
entity && game.editor.selectedEntities.push(entity); if (entity) {
} else { game.editor.selectedEntities.push(entity);
}
}
else {
const index = entities.findIndex(e => includes(game.editor.selectedEntities, e)); const index = entities.findIndex(e => includes(game.editor.selectedEntities, e));
const entity = entities[(index + 1) % entities.length]; const entity = entities[(index + 1) % entities.length];
game.editor.selectedEntities = entity ? [entity] : []; game.editor.selectedEntities = entity ? [entity] : [];
@@ -227,7 +243,8 @@ export function editorDragEntities(game: PonyTownGame, hover: Point, buttonPress
e.x = roundPositionX(e.draggingStart!.x + dx); e.x = roundPositionX(e.draggingStart!.x + dx);
e.y = roundPositionY(e.draggingStart!.y + dy); e.y = roundPositionY(e.draggingStart!.y + dy);
}); });
} else { }
else {
game.apply(() => game.editor.draggingEntities = false); game.apply(() => game.editor.draggingEntities = false);
game.send(server => server.editorAction({ game.send(server => server.editorAction({
type: 'move', type: 'move',
+10 -5
View File
@@ -5,29 +5,34 @@ try {
if (!('performance' in window && 'now' in performance)) { if (!('performance' in window && 'now' in performance)) {
(window as any).performance = Date; (window as any).performance = Date;
} }
} catch { } }
catch { }
try { try {
if (!('getGamepads' in navigator)) { if (!('getGamepads' in navigator)) {
(window.navigator as any).getGamepads = () => []; (window.navigator as any).getGamepads = () => [];
} }
} catch { } }
catch { }
try { try {
if (!('requestAnimationFrame' in window)) { if (!('requestAnimationFrame' in window)) {
(window as any).requestAnimationFrame = (callback: any) => setTimeout(() => callback(performance.now()), 1000 / 60) as any; (window as any).requestAnimationFrame = (callback: any) => setTimeout(() => callback(performance.now()), 1000 / 60) as any;
} }
} catch { } }
catch { }
try { try {
if (!('cancelAnimationFrame' in window)) { if (!('cancelAnimationFrame' in window)) {
(window as any).cancelAnimationFrame = clearTimeout; (window as any).cancelAnimationFrame = clearTimeout;
} }
} catch { } }
catch { }
// IE <= 10 // IE <= 10
try { try {
if (!('devicePixelRatio' in window)) { if (!('devicePixelRatio' in window)) {
(window as any).devicePixelRatio = 1; (window as any).devicePixelRatio = 1;
} }
} catch { } }
catch { }
+42 -20
View File
@@ -162,7 +162,9 @@ export function updatePonyInfo(pony: Pony, info: string | Uint8Array, apply: ()
pony.discardBatch = true; pony.discardBatch = true;
if (isPonyFlying(pony) && !canPonyFly(pony)) { if (isPonyFlying(pony) && !canPonyFly(pony)) {
DEVELOPMENT && console.warn('Force land'); if (DEVELOPMENT) {
console.warn('Force land');
}
pony.state = setFlag(pony.state, EntityState.PonyFlying, false); pony.state = setFlag(pony.state, EntityState.PonyFlying, false);
resetAnimatorState(pony.animator); resetAnimatorState(pony.animator);
} }
@@ -201,7 +203,8 @@ export function doBoopPonyAction(game: PonyTownGame, pony: Pony) {
if (pony.swimming && pony.lastBoopSplash < performance.now()) { if (pony.swimming && pony.lastBoopSplash < performance.now()) {
if (isFacingRight(pony)) { if (isFacingRight(pony)) {
playEffect(game, pony, boopSplashRight.type); playEffect(game, pony, boopSplashRight.type);
} else { }
else {
playEffect(game, pony, boopSplashLeft.type); playEffect(game, pony, boopSplashLeft.type);
} }
@@ -242,13 +245,15 @@ export function drawPonyEntity(batch: PaletteSpriteBatch, pony: Pony, drawOption
if (pony.batch !== undefined) { if (pony.batch !== undefined) {
batch.patchBatchDepth(pony.batch); batch.patchBatchDepth(pony.batch);
batch.drawBatch(pony.batch); batch.drawBatch(pony.batch);
} else if (pony.palettePonyInfo !== undefined) { }
else if (pony.palettePonyInfo !== undefined) {
let swimming = false; let swimming = false;
if (isSwimmingState(pony.animator.state)) { if (isSwimmingState(pony.animator.state)) {
if (pony.animator.state === swimmingToFlying) { if (pony.animator.state === swimmingToFlying) {
swimming = pony.animator.time < 0.4; swimming = pony.animator.time < 0.4;
} else { }
else {
swimming = true; swimming = true;
} }
} }
@@ -294,7 +299,9 @@ export function drawPonyEntity(batch: PaletteSpriteBatch, pony: Pony, drawOption
if (pony.magicEffect.currentAnimation !== undefined) { if (pony.magicEffect.currentAnimation !== undefined) {
drawAnimation(batch, pony.magicEffect, 0, 0, pony.magicColor, flip); drawAnimation(batch, pony.magicEffect, 0, 0, pony.magicColor, flip);
const sprite = sprites.magic3.frames[pony.magicEffect.frame]; const sprite = sprites.magic3.frames[pony.magicEffect.frame];
sprite && batch.drawSprite(sprite, WHITE, pony.heartsEffect.palette, 0, 0); if (sprite) {
batch.drawSprite(sprite, WHITE, pony.heartsEffect.palette, 0, 0);
}
} }
} }
@@ -384,13 +391,16 @@ export function flagsToState(state: EntityState, moving: boolean, isSwimming: bo
if (isSwimming) { if (isSwimming) {
return swimming; return swimming;
} else if (moving) { }
else if (moving) {
if (ponyState === EntityState.PonyFlying) { if (ponyState === EntityState.PonyFlying) {
return flying; return flying;
} else { }
else {
return trotting; return trotting;
} }
} else { }
else {
switch (ponyState) { switch (ponyState) {
case EntityState.PonyStanding: return standing; case EntityState.PonyStanding: return standing;
case EntityState.PonyWalking: return trotting; case EntityState.PonyWalking: return trotting;
@@ -435,7 +445,8 @@ export function updatePonyEntity(pony: Pony, delta: number, gameTime: number, sa
} }
pony.doAction = DoAction.None; pony.doAction = DoAction.None;
} else { }
else {
setAnimatorState(pony.animator, animationState); setAnimatorState(pony.animator, animationState);
} }
@@ -448,7 +459,8 @@ export function updatePonyEntity(pony: Pony, delta: number, gameTime: number, sa
if (frame >= pony.headAnimation.frames.length && !pony.headAnimation.loop) { if (frame >= pony.headAnimation.frames.length && !pony.headAnimation.loop) {
pony.headAnimation = undefined; pony.headAnimation = undefined;
state.headAnimationFrame = 0; state.headAnimationFrame = 0;
} else { }
else {
state.headAnimationFrame = frame % pony.headAnimation.frames.length; state.headAnimationFrame = frame % pony.headAnimation.frames.length;
} }
} }
@@ -468,7 +480,8 @@ export function updatePonyEntity(pony: Pony, delta: number, gameTime: number, sa
if ((pony.state & EntityState.Magic) !== 0) { if ((pony.state & EntityState.Magic) !== 0) {
playAnimation(pony.magicEffect, magicAnimation); playAnimation(pony.magicEffect, magicAnimation);
} else { }
else {
playAnimation(pony.magicEffect, undefined); playAnimation(pony.magicEffect, undefined);
} }
@@ -546,11 +559,13 @@ export function updatePonyHold(pony: Pony, game: PonyTownGame) {
if (pony.hold !== 0) { if (pony.hold !== 0) {
if (ponyState.holding === undefined) { if (ponyState.holding === undefined) {
ponyState.holding = createAnEntity(pony.hold, 0, 0, 0, {}, pony.paletteManager, game); ponyState.holding = createAnEntity(pony.hold, 0, 0, 0, {}, pony.paletteManager, game);
} else if (ponyState.holding.type !== pony.hold) { }
else if (ponyState.holding.type !== pony.hold) {
releaseEntity(ponyState.holding); releaseEntity(ponyState.holding);
ponyState.holding = createAnEntity(pony.hold, 0, 0, 0, {}, pony.paletteManager, game); ponyState.holding = createAnEntity(pony.hold, 0, 0, 0, {}, pony.paletteManager, game);
} }
} else if (ponyState.holding !== undefined) { }
else if (ponyState.holding !== undefined) {
releaseEntity(ponyState.holding); releaseEntity(ponyState.holding);
ponyState.holding = undefined; ponyState.holding = undefined;
} }
@@ -590,7 +605,8 @@ function filterExpression(expression: Expression) {
if (expression.muzzle === Muzzle.SmilePant) { if (expression.muzzle === Muzzle.SmilePant) {
expression.muzzle = Muzzle.SmileOpen; expression.muzzle = Muzzle.SmileOpen;
} else if (expression.muzzle === Muzzle.NeutralPant) { }
else if (expression.muzzle === Muzzle.NeutralPant) {
expression.muzzle = Muzzle.NeutralOpen2; expression.muzzle = Muzzle.NeutralOpen2;
} }
} }
@@ -598,9 +614,11 @@ function filterExpression(expression: Expression) {
if (blush) { if (blush) {
if (expression.muzzle === Muzzle.SmileOpen2) { if (expression.muzzle === Muzzle.SmileOpen2) {
expression.muzzle = Muzzle.SmileOpen; expression.muzzle = Muzzle.SmileOpen;
} else if (expression.muzzle === Muzzle.FrownOpen) { }
else if (expression.muzzle === Muzzle.FrownOpen) {
expression.muzzle = Muzzle.ConcernedOpen; expression.muzzle = Muzzle.ConcernedOpen;
} else if (expression.muzzle === Muzzle.NeutralOpen2) { }
else if (expression.muzzle === Muzzle.NeutralOpen2) {
expression.muzzle = Muzzle.Oh; expression.muzzle = Muzzle.Oh;
} }
} }
@@ -619,21 +637,25 @@ function updatePonyExpression(pony: Pony, expr: number, safe: boolean) {
if (hasFlag(extra, ExpressionExtra.Cry)) { if (hasFlag(extra, ExpressionExtra.Cry)) {
playAnimation(pony.cryEffect, cryAnimation); playAnimation(pony.cryEffect, cryAnimation);
} else if (hasFlag(extra, ExpressionExtra.Tears)) { }
else if (hasFlag(extra, ExpressionExtra.Tears)) {
playAnimation(pony.cryEffect, tearsAnimation); playAnimation(pony.cryEffect, tearsAnimation);
} else { }
else {
playAnimation(pony.cryEffect, undefined); playAnimation(pony.cryEffect, undefined);
} }
if (hasFlag(extra, ExpressionExtra.Zzz)) { if (hasFlag(extra, ExpressionExtra.Zzz)) {
playOneOfAnimations(pony.zzzEffect, zzzAnimations); playOneOfAnimations(pony.zzzEffect, zzzAnimations);
} else { }
else {
playAnimation(pony.zzzEffect, undefined); playAnimation(pony.zzzEffect, undefined);
} }
if (hasFlag(extra, ExpressionExtra.Hearts)) { if (hasFlag(extra, ExpressionExtra.Hearts)) {
playAnimation(pony.heartsEffect, heartsAnimation); playAnimation(pony.heartsEffect, heartsAnimation);
} else { }
else {
playAnimation(pony.heartsEffect, undefined); playAnimation(pony.heartsEffect, undefined);
} }
} }
+29 -11
View File
@@ -112,7 +112,8 @@ export function createHeadTransform(
) { ) {
if (originalTransform !== undefined) { if (originalTransform !== undefined) {
copyMat2D(headTransform, originalTransform); copyMat2D(headTransform, originalTransform);
} else { }
else {
identityMat2D(headTransform); identityMat2D(headTransform);
} }
@@ -140,7 +141,8 @@ const hairOffsets = [
function draw(options: Options, flag: NoDraw) { function draw(options: Options, flag: NoDraw) {
if (TOOLS) { if (TOOLS) {
return !hasFlag(options.no, flag); return !hasFlag(options.no, flag);
} else { }
else {
return true; return true;
} }
} }
@@ -274,13 +276,17 @@ export function drawPony(batch: Batch, info: Info, state: State, ponyX: number,
// selection // selection
if (options.selected) { if (options.selected) {
const sprite = at(sprites.ponySelections, shadow.frame); const sprite = at(sprites.ponySelections, shadow.frame);
sprite && batch.drawSprite(sprite, WHITE, info.defaultPalette, shadowX, shadowY); if (sprite) {
batch.drawSprite(sprite, WHITE, info.defaultPalette, shadowX, shadowY);
}
} }
// shadow // shadow
if (options.shadow) { if (options.shadow) {
const sprite = at(sprites.ponyShadows, shadow.frame); const sprite = at(sprites.ponyShadows, shadow.frame);
sprite && batch.drawSprite(sprite, options.shadowColor, info.defaultPalette, shadowX, shadowY); if (sprite) {
batch.drawSprite(sprite, options.shadowColor, info.defaultPalette, shadowX, shadowY);
}
} }
// head accessory // head accessory
@@ -522,7 +528,8 @@ export function drawHead(
if (toy !== undefined) { if (toy !== undefined) {
drawSet(batch, sprites.extraAccessoriesBehind, toy, extraX, extraY, WHITE); drawSet(batch, sprites.extraAccessoriesBehind, toy, extraX, extraY, WHITE);
} else if (options.extra && draw(options, NoDraw.Behind)) { }
else if (options.extra && draw(options, NoDraw.Behind)) {
drawSet(batch, sprites.extraAccessoriesBehind, info.extraAccessory, extraX, extraY, WHITE); drawSet(batch, sprites.extraAccessoriesBehind, info.extraAccessory, extraX, extraY, WHITE);
} }
@@ -615,7 +622,9 @@ export function drawHead(
const noses = at(sprites.noses, muzzle); const noses = at(sprites.noses, muzzle);
const nose = att(noses, info.nose && info.nose.type)![0]; const nose = att(noses, info.nose && info.nose.type)![0];
nose.mouth && batch.drawSprite(nose.mouth, WHITE, info.defaultPalette, x, y); if (nose.mouth) {
batch.drawSprite(nose.mouth, WHITE, info.defaultPalette, x, y);
}
if (holding !== undefined && holding.draw !== undefined) { if (holding !== undefined && holding.draw !== undefined) {
holding.x = toWorldX(x + toInt(holding.pickableX)); holding.x = toWorldX(x + toInt(holding.pickableX));
@@ -647,7 +656,8 @@ export function drawHead(
if (toy !== undefined) { if (toy !== undefined) {
drawSet(batch, sprites.extraAccessories, toy, extraX, extraY, WHITE); drawSet(batch, sprites.extraAccessories, toy, extraX, extraY, WHITE);
} else if (options.extra && draw(options, NoDraw.Front)) { }
else if (options.extra && draw(options, NoDraw.Front)) {
drawSet(batch, sprites.extraAccessories, info.extraAccessory, extraX, extraY, WHITE); drawSet(batch, sprites.extraAccessories, info.extraAccessory, extraX, extraY, WHITE);
} }
@@ -770,13 +780,21 @@ function drawEye(
) { ) {
if (eye !== undefined) { if (eye !== undefined) {
if (info.eyeshadow === true) { if (info.eyeshadow === true) {
eye.shadow && batch.drawSprite(eye.shadow, WHITE, info.eyeshadowColor, x, y); if (eye.shadow) {
eye.shine && batch.drawSprite(eye.shine, SHINES_COLOR, info.defaultPalette, x, y); batch.drawSprite(eye.shadow, WHITE, info.eyeshadowColor, x, y);
}
if (eye.shine) {
batch.drawSprite(eye.shine, SHINES_COLOR, info.defaultPalette, x, y);
}
} }
eye.base && batch.drawSprite(eye.base, WHITE, eyePalette, x, y); if (eye.base) {
batch.drawSprite(eye.base, WHITE, eyePalette, x, y);
}
const sprite = at(eye.irises, iris); const sprite = at(eye.irises, iris);
sprite && batch.drawSprite(sprite, WHITE, palette, x, y); if (sprite) {
batch.drawSprite(sprite, WHITE, palette, x, y);
}
} }
} }
+4 -2
View File
@@ -2,11 +2,13 @@ import { REV } from '../generated/rev';
/* istanbul ignore next */ /* istanbul ignore next */
export function getUrl(name: string): string { export function getUrl(name: string): string {
if (DEVELOPMENT) if (DEVELOPMENT) {
return `/assets/${name}`; return `/assets/${name}`;
}
if (!REV[name]) if (!REV[name]) {
throw new Error(`Cannot find file url (${name})`); throw new Error(`Cannot find file url (${name})`);
}
return `/assets/${name.replace(/(\.\S+)$/, `-${REV[name]}$1`)}`; return `/assets/${name.replace(/(\.\S+)$/, `-${REV[name]}$1`)}`;
} }
+3 -1
View File
@@ -33,7 +33,9 @@ export function restorePlayerPosition() {
if (currentPlayer.x !== setX || currentPlayer.y !== setY) { if (currentPlayer.x !== setX || currentPlayer.y !== setY) {
currentPlayer.x = setX; currentPlayer.x = setX;
currentPlayer.y = setY; currentPlayer.y = setY;
DEVELOPMENT && console.warn('Restoring player position'); if (DEVELOPMENT) {
console.warn('Restoring player position');
}
} }
} }
} }
+5 -2
View File
@@ -68,8 +68,11 @@ export function initWebGLResources(gl: WebGLRenderingContext, paletteManager: Pa
try { try {
createFrameBuffer(gl, frameBuffer, camera.w, camera.h, true, null); createFrameBuffer(gl, frameBuffer, camera.w, camera.h, true, null);
createFrameBuffer(gl, frameBuffer2, camera.w, camera.h, false, frameBuffer.depthStencilRenderbuffer); createFrameBuffer(gl, frameBuffer2, camera.w, camera.h, false, frameBuffer.depthStencilRenderbuffer);
} catch (e) { }
DEVELOPMENT && console.warn(e); catch (e) {
if (DEVELOPMENT) {
console.warn(e);
}
failedFBO = true; failedFBO = true;
failedDepthBuffer = true; failedDepthBuffer = true;
} }
+45 -20
View File
@@ -105,7 +105,8 @@ function pickEntity(
function pickByBounds(entity: Entity, rect: Rect, pickHidden: boolean): boolean { function pickByBounds(entity: Entity, rect: Rect, pickHidden: boolean): boolean {
if ((entity.flags & EntityFlags.Interactive) === 0 || (isHidden(entity) && !pickHidden)) { if ((entity.flags & EntityFlags.Interactive) === 0 || (isHidden(entity) && !pickHidden)) {
return false; return false;
} else { }
else {
const bounds = entity.interactBounds || entity.bounds; const bounds = entity.interactBounds || entity.bounds;
return !!bounds && boundsIntersect(entity.x, entity.y, bounds, 0, 0, rect); return !!bounds && boundsIntersect(entity.x, entity.y, bounds, 0, 0, rect);
} }
@@ -128,8 +129,9 @@ export function pickEntitiesByRect(map: WorldMap, rect: Rect, ignorePonies: bool
} }
export function removeRegions(map: WorldMap, coords: number[]) { export function removeRegions(map: WorldMap, coords: number[]) {
if (coords.length === 0) if (coords.length === 0) {
return; return;
}
const entitiesToRemove = new Set<Entity>(); const entitiesToRemove = new Set<Entity>();
@@ -161,7 +163,9 @@ export function setRegion(map: WorldMap, x: number, y: number, region: Region) {
const oldRegion = map.regions[index]; const oldRegion = map.regions[index];
if (oldRegion) { if (oldRegion) {
DEVELOPMENT && !TESTS && console.error(`Region already set (${x}, ${y})`); if (DEVELOPMENT && !TESTS) {
console.error(`Region already set (${x}, ${y})`);
}
for (const e of oldRegion.entities.slice()) { for (const e of oldRegion.entities.slice()) {
releaseAndRemoveEntityFromMap(map, e); releaseAndRemoveEntityFromMap(map, e);
@@ -172,8 +176,11 @@ export function setRegion(map: WorldMap, x: number, y: number, region: Region) {
setTilesDirty(map, x * REGION_SIZE - 1, y * REGION_SIZE - 1, REGION_SIZE + 2, REGION_SIZE + 2); setTilesDirty(map, x * REGION_SIZE - 1, y * REGION_SIZE - 1, REGION_SIZE + 2, REGION_SIZE + 2);
map.regions[index] = region; map.regions[index] = region;
updateMinMaxRegion(map); updateMinMaxRegion(map);
} else { }
DEVELOPMENT && !TESTS && console.error(`Invalid region coords (${x}, ${y})`); else {
if (DEVELOPMENT && !TESTS) {
console.error(`Invalid region coords (${x}, ${y})`);
}
} }
} }
@@ -186,7 +193,8 @@ export function addEntity(map: WorldMap, entity: Entity) {
if (!region) { if (!region) {
throw new Error(`Missing region at ${entity.x} ${entity.y}`); throw new Error(`Missing region at ${entity.x} ${entity.y}`);
} else { }
else {
addEntityToMapRegion(map, region, entity); addEntityToMapRegion(map, region, entity);
} }
} }
@@ -209,7 +217,8 @@ export function removeEntityDirectly(map: WorldMap, entity: Entity) {
releaseEntity(entity); releaseEntity(entity);
removeEntityFromEntities(map, entity); removeEntityFromEntities(map, entity);
return false; return false;
} else { }
else {
return true; return true;
} }
}); });
@@ -286,9 +295,11 @@ export function addEntityToMapRegion(map: WorldMap, region: Region, entity: Enti
const existing = map.entitiesById.get(entity.id); const existing = map.entitiesById.get(entity.id);
if (existing) { if (existing) {
DEVELOPMENT && !TESTS && console.error(`Adding duplicate entity ${entity.id} (` + if (DEVELOPMENT && !TESTS) {
console.error(`Adding duplicate entity ${entity.id} (` +
`${worldToRegionX(existing.x, map)}, ${worldToRegionY(existing.y, map)} => ` + `${worldToRegionX(existing.x, map)}, ${worldToRegionY(existing.y, map)} => ` +
`${worldToRegionX(entity.x, map)}, ${worldToRegionY(entity.y, map)})`); `${worldToRegionX(entity.x, map)}, ${worldToRegionY(entity.y, map)})`);
}
removeEntity(map, existing); removeEntity(map, existing);
} }
@@ -419,7 +430,8 @@ export function updateEntitiesCoverLifted(map: WorldMap, player: Entity, hideObj
if (e.coverLifted && lifting < 1) { if (e.coverLifted && lifting < 1) {
e.coverLifting = Math.min(lifting + delta * 2, 1); e.coverLifting = Math.min(lifting + delta * 2, 1);
} else if (!e.coverLifted && lifting > 0) { }
else if (!e.coverLifted && lifting > 0) {
e.coverLifting = Math.max(lifting - delta * 2, 0); e.coverLifting = Math.max(lifting - delta * 2, 0);
} }
} }
@@ -460,7 +472,9 @@ export function getMapHeightAt(map: WorldMap, x: number, y: number, gameTime: nu
} }
export function updateEntities(game: PonyTownGame, gameTime: number, delta: number, safe: boolean) { export function updateEntities(game: PonyTownGame, gameTime: number, delta: number, safe: boolean) {
TIMING && timeStart('updateEntities'); if (TIMING) {
timeStart('updateEntities');
}
const map = game.map; const map = game.map;
@@ -475,7 +489,8 @@ export function updateEntities(game: PonyTownGame, gameTime: number, delta: numb
const bobs = entity.bobs!; const bobs = entity.bobs!;
const frame = (((gameTime / 1000) * entity.bobsFps!) | 0) % bobs.length; const frame = (((gameTime / 1000) * entity.bobsFps!) | 0) % bobs.length;
entity.z = toWorldZ(bobs[frame]); entity.z = toWorldZ(bobs[frame]);
} else if ((flags & EntityFlags.StaticY) === 0) { }
else if ((flags & EntityFlags.StaticY) === 0) {
entity.z = getMapHeightAt(map, entity.x, entity.y, gameTime); entity.z = getMapHeightAt(map, entity.x, entity.y, gameTime);
} }
@@ -489,11 +504,13 @@ export function updateEntities(game: PonyTownGame, gameTime: number, delta: numb
if (wasSwimming !== pony.swimming) { if (wasSwimming !== pony.swimming) {
if (isFlyingDown(pony.animator.state)) { if (isFlyingDown(pony.animator.state)) {
setTimeout(() => playEffect(game, pony, splash.type), 400); setTimeout(() => playEffect(game, pony, splash.type), 400);
} else { }
else {
playEffect(game, pony, splash.type); playEffect(game, pony, splash.type);
} }
} }
} else if (entity.update !== undefined) { }
else if (entity.update !== undefined) {
entity.update(delta, gameTime); entity.update(delta, gameTime);
} }
@@ -516,7 +533,8 @@ export function updateEntities(game: PonyTownGame, gameTime: number, delta: numb
if (Math.abs(entity.lightScale! - entity.lightTarget!) < move) { if (Math.abs(entity.lightScale! - entity.lightTarget!) < move) {
entity.lightScale = entity.lightTarget; entity.lightScale = entity.lightTarget;
entity.lightTarget = 1 - Math.random() * 0.15; entity.lightTarget = 1 - Math.random() * 0.15;
} else { }
else {
entity.lightScale! += entity.lightScale! < entity.lightTarget! ? move : -move; entity.lightScale! += entity.lightScale! < entity.lightTarget! ? move : -move;
} }
} }
@@ -538,7 +556,9 @@ export function updateEntities(game: PonyTownGame, gameTime: number, delta: numb
} }
} }
TIMING && timeEnd(); if (TIMING) {
timeEnd();
}
} }
export function invalidatePalettes(entities: Entity[]) { export function invalidatePalettes(entities: Entity[]) {
@@ -552,8 +572,9 @@ export function invalidatePalettes(entities: Entity[]) {
export function ensureAllVisiblePoniesAreDecoded(map: WorldMap, camera: Camera, paletteManager: PaletteManager) { export function ensureAllVisiblePoniesAreDecoded(map: WorldMap, camera: Camera, paletteManager: PaletteManager) {
const poniesToDecode = map.poniesToDecode; const poniesToDecode = map.poniesToDecode;
if (!poniesToDecode.length) if (!poniesToDecode.length) {
return; return;
}
const decode = new Set<number>(); const decode = new Set<number>();
@@ -565,8 +586,9 @@ export function ensureAllVisiblePoniesAreDecoded(map: WorldMap, camera: Camera,
} }
} }
if (!decode.size) if (!decode.size) {
return; return;
}
if (decode.size > 100) { if (decode.size > 100) {
paletteManager.deduplicate = false; paletteManager.deduplicate = false;
@@ -575,10 +597,12 @@ export function ensureAllVisiblePoniesAreDecoded(map: WorldMap, camera: Camera,
map.poniesToDecode = poniesToDecode.filter((pony, i) => { map.poniesToDecode = poniesToDecode.filter((pony, i) => {
if (pony.palettePonyInfo !== undefined) { if (pony.palettePonyInfo !== undefined) {
return false; return false;
} else if (decode.has(i)) { }
else if (decode.has(i)) {
ensurePonyInfoDecoded(pony); ensurePonyInfoDecoded(pony);
return false; return false;
} else { }
else {
return true; return true;
} }
}); });
@@ -595,7 +619,8 @@ export function switchEntityRegion(map: WorldMap, entity: Entity, x: number, y:
if (region) { if (region) {
addEntityToRegion(region, entity, map); addEntityToRegion(region, entity, map);
} else { }
else {
releaseAndRemoveEntityFromMap(map, entity); releaseAndRemoveEntityFromMap(map, entity);
} }
} }
+12 -6
View File
@@ -41,13 +41,17 @@ function meetsSupporterRequirement(account: AccountSupporter, require: string):
if (require === 'inv') { if (require === 'inv') {
return modOrDev || level >= 1 || !!account.supporterInvited; return modOrDev || level >= 1 || !!account.supporterInvited;
} else if (require === 'sup1') { }
else if (require === 'sup1') {
return modOrDev || level >= 1; return modOrDev || level >= 1;
} else if (require === 'sup2') { }
else if (require === 'sup2') {
return modOrDev || level >= 2; return modOrDev || level >= 2;
} else if (require === 'sup3') { }
else if (require === 'sup3') {
return modOrDev || level >= 3; return modOrDev || level >= 3;
} else { }
else {
return false; return false;
} }
} }
@@ -60,7 +64,8 @@ export function getCharacterLimit(account: AccountSupporter) {
default: default:
if (hasFlag(account.flags, AccountDataFlags.PastSupporter)) { if (hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
return BASE_CHARACTER_LIMIT + ADDITIONAL_CHARACTERS_PAST_SUPPORTER; return BASE_CHARACTER_LIMIT + ADDITIONAL_CHARACTERS_PAST_SUPPORTER;
} else { }
else {
return BASE_CHARACTER_LIMIT; return BASE_CHARACTER_LIMIT;
} }
} }
@@ -69,7 +74,8 @@ export function getCharacterLimit(account: AccountSupporter) {
export function getSupporterInviteLimit(account: AccountSupporter) { export function getSupporterInviteLimit(account: AccountSupporter) {
if (isMod(account) || isDev(account)) { if (isMod(account) || isDev(account)) {
return 100; return 100;
} else { }
else {
switch (account.supporter) { switch (account.supporter) {
case 1: return 1; case 1: return 1;
case 2: return 5; case 2: return 5;
+3 -4
View File
@@ -352,6 +352,7 @@ export const enum SupporterFlags {
Supporter1 = 1, Supporter1 = 1,
Supporter2 = 2, Supporter2 = 2,
Supporter3 = 3, Supporter3 = 3,
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
SupporterMask = 0x0003, SupporterMask = 0x0003,
IgnorePatreon = 0x0080, IgnorePatreon = 0x0080,
PastSupporter = 0x0100, PastSupporter = 0x0100,
@@ -489,11 +490,9 @@ export const eventFields: (keyof Event)[] = [
// models // models
export interface OriginInfo extends OriginInfoBase { export type OriginInfo = OriginInfoBase;
}
export interface Timestamps extends TimestampsBase { export type Timestamps = TimestampsBase;
}
export interface AccountStatus { export interface AccountStatus {
online: boolean; online: boolean;
+54 -27
View File
@@ -31,9 +31,11 @@ export function compareAuths(a: Auth, b: Auth) {
if (aDeleted && !bDeleted) { if (aDeleted && !bDeleted) {
return 1; return 1;
} else if (!aDeleted && bDeleted) { }
else if (!aDeleted && bDeleted) {
return -1; return -1;
} else { }
else {
return compareByName(a, b); return compareByName(a, b);
} }
} }
@@ -82,7 +84,8 @@ export function filterAccounts(items: Account[], search: string, showOnly: strin
if (filter) { if (filter) {
if (not) { if (not) {
items = items.filter(i => !filter(i)); items = items.filter(i => !filter(i));
} else { }
else {
items = items.filter(filter); items = items.filter(filter);
} }
} }
@@ -106,20 +109,27 @@ export function createFilter(search: string): (account: Account) => boolean {
} }
function filter(account: Account): boolean { function filter(account: Account): boolean {
if (account._id === search) if (account._id === search) {
return true; return true;
if (test(account.name)) }
if (test(account.name)) {
return true; return true;
if (test(account.note)) }
if (test(account.note)) {
return true; return true;
if (account.roles && account.roles.some(test)) }
if (account.roles && account.roles.some(test)) {
return true; return true;
if (account.emails && account.emails.some(test)) }
if (account.emails && account.emails.some(test)) {
return true; return true;
if (account.auths && account.auths.some(testAuth)) }
if (account.auths && account.auths.some(testAuth)) {
return true; return true;
if (account.merges && account.merges.some(testMerge)) }
if (account.merges && account.merges.some(testMerge)) {
return true; return true;
}
return false; return false;
} }
@@ -165,8 +175,9 @@ export function createPotentialDuplicatesFilter(getAccountsByBrowserId: (id: str
return i => { return i => {
const name = i.nameLower; const name = i.nameLower;
if (name === 'anonymous' || !i.lastBrowserId) if (name === 'anonymous' || !i.lastBrowserId) {
return false; return false;
}
const accounts = getAccountsByBrowserId(i.lastBrowserId); const accounts = getAccountsByBrowserId(i.lastBrowserId);
@@ -187,15 +198,20 @@ export function createFilter2(showOnly: string): ((account: Account) => boolean)
if (showOnly === 'banned') { if (showOnly === 'banned') {
return hasAnyBan; return hasAnyBan;
} else if (showOnly === 'timed out') { }
else if (showOnly === 'timed out') {
return i => !!((i.mute && i.mute > now) || (i.shadow && i.shadow > now) || (i.ban && i.ban > now)); return i => !!((i.mute && i.mute > now) || (i.shadow && i.shadow > now) || (i.ban && i.ban > now));
} else if (showOnly === 'with flags') { }
else if (showOnly === 'with flags') {
return i => !!i.flags; return i => !!i.flags;
} else if (showOnly === 'notes') { }
else if (showOnly === 'notes') {
return i => !!i.note; return i => !!i.note;
} else if (showOnly === 'supporters') { }
else if (showOnly === 'supporters') {
return i => !!(i.patreon || i.supporter || i.supporterDeclinedSince); return i => !!(i.patreon || i.supporter || i.supporterDeclinedSince);
} else { }
else {
return undefined; return undefined;
} }
} }
@@ -206,7 +222,8 @@ export function getPotentialDuplicates(account: Account, getAccountsByBrowserId:
if (accounts !== undefined && accounts.length > 1 && name !== 'anonymous') { if (accounts !== undefined && accounts.length > 1 && name !== 'anonymous') {
return accounts.filter(a => a !== account && a.nameLower === name); return accounts.filter(a => a !== account && a.nameLower === name);
} else { }
else {
return []; return [];
} }
} }
@@ -214,18 +231,24 @@ export function getPotentialDuplicates(account: Account, getAccountsByBrowserId:
// duplicates // duplicates
export function compareDuplicates(a: DuplicateBase, b: DuplicateBase): number { export function compareDuplicates(a: DuplicateBase, b: DuplicateBase): number {
if (a.note !== b.note) if (a.note !== b.note) {
return b.note - a.note; return b.note - a.note;
if (a.emails !== b.emails) }
if (a.emails !== b.emails) {
return b.emails - a.emails; return b.emails - a.emails;
if (a.name !== b.name) }
if (a.name !== b.name) {
return b.name - a.name; return b.name - a.name;
if (a.browserId !== b.browserId) }
if (a.browserId !== b.browserId) {
return a.browserId ? -1 : 1; return a.browserId ? -1 : 1;
if (a.origins !== b.origins) }
if (a.origins !== b.origins) {
return b.origins - a.origins; return b.origins - a.origins;
if (a.ponies !== b.ponies) }
if (a.ponies !== b.ponies) {
return (b.ponies ? b.ponies.length : 0) - (a.ponies ? a.ponies.length : 0); return (b.ponies ? b.ponies.length : 0) - (a.ponies ? a.ponies.length : 0);
}
return b.lastVisit.getTime() - a.lastVisit.getTime(); return b.lastVisit.getTime() - a.lastVisit.getTime();
} }
@@ -236,7 +259,8 @@ export function emailName(email: string): string {
export function createEmailMatcher(emails: string[]): ((email: string) => boolean) | undefined { export function createEmailMatcher(emails: string[]): ((email: string) => boolean) | undefined {
if (!emails || !emails.length) { if (!emails || !emails.length) {
return undefined; return undefined;
} else { }
else {
const match = emails.map(emailName).map(escapeRegExp).join('|'); const match = emails.map(emailName).map(escapeRegExp).join('|');
const regex = new RegExp(`^(?:${match})@`, 'i'); const regex = new RegExp(`^(?:${match})@`, 'i');
return email => regex.test(email); return email => regex.test(email);
@@ -296,7 +320,8 @@ export function duplicatesCollector(duplicates: string[]) {
return (item: string) => { return (item: string) => {
if (set.has(item)) { if (set.has(item)) {
duplicates.push(item); duplicates.push(item);
} else { }
else {
set.add(item); set.add(item);
} }
}; };
@@ -393,7 +418,8 @@ export function addToMap<T>(map: Map<string, T[]>, key: string, item: T) {
if (items) { if (items) {
items.push(item); items.push(item);
} else { }
else {
map.set(key, [item]); map.set(key, [item]);
} }
} }
@@ -426,7 +452,8 @@ export function createIdStore() {
if (result) { if (result) {
return result; return result;
} else { }
else {
idsMap.set(id, id); idsMap.set(id, id);
return id; return id;
} }
+8 -4
View File
@@ -34,13 +34,15 @@ export function playAnimation(player: AnimationPlayer, animation: SpriteAnimatio
player.time = (player.frame + 1) / player.currentAnimation.fps; player.time = (player.frame + 1) / player.currentAnimation.fps;
player.phase = AnimationPhase.Ending; player.phase = AnimationPhase.Ending;
} }
} else { }
else {
player.currentAnimation = animation; player.currentAnimation = animation;
player.time = 0; player.time = 0;
player.phase = AnimationPhase.Starting; player.phase = AnimationPhase.Starting;
} }
player.dirty = true; player.dirty = true;
} else if (player.phase === AnimationPhase.Ending) { }
else if (player.phase === AnimationPhase.Ending) {
player.nextAnimation = animation; player.nextAnimation = animation;
player.dirty = true; player.dirty = true;
} }
@@ -95,12 +97,14 @@ export function drawAnimation(
throw new Error('Undefined frame in sprite animation'); throw new Error('Undefined frame in sprite animation');
} }
if (!frame) // TEMP if (!frame) { // TEMP
return; return;
}
if (maxY === 0) { if (maxY === 0) {
batch.drawSprite(frame, color, player.palette, x, y); batch.drawSprite(frame, color, player.palette, x, y);
} else { }
else {
drawSpriteCropped(batch, frame, color, player.palette, x, y, maxY); drawSpriteCropped(batch, frame, color, player.palette, x, y, maxY);
} }
} }
+6 -3
View File
@@ -71,10 +71,12 @@ export function setAnimatorState<T extends Animation>(animator: Animator<T>, sta
if (animator.state !== state) { if (animator.state !== state) {
if (animator.state === undefined) { if (animator.state === undefined) {
animator.state = state; animator.state = state;
} else { }
else {
animator.target = state; animator.target = state;
} }
} else { }
else {
animator.target = undefined; animator.target = undefined;
} }
@@ -106,7 +108,8 @@ export function updateAnimator<T extends Animation>(animator: Animator<T>, delta
if (frameTimeAfter >= exitAfter || animationEnded) { if (frameTimeAfter >= exitAfter || animationEnded) {
if (!transition.keepTime) { if (!transition.keepTime) {
animator.time = transition.enterTime || 0; animator.time = transition.enterTime || 0;
} else { }
else {
animator.time = animator.time % animationLength; animator.time = animator.time % animationLength;
} }
+30 -14
View File
@@ -10,10 +10,12 @@ export function writeBinary(write: (writer: BinaryWriter) => void): Uint8Array {
try { try {
write(writer); write(writer);
break; break;
} catch (e) { }
catch (e) {
if (e instanceof RangeError || isDataViewError(e)) { if (e instanceof RangeError || isDataViewError(e)) {
resizeWriter(writer); resizeWriter(writer);
} else { }
else {
throw e; throw e;
} }
} }
@@ -23,7 +25,9 @@ export function writeBinary(write: (writer: BinaryWriter) => void): Uint8Array {
} }
export function decodeString(value: DataView | null, offset: number, length: number): string | null { export function decodeString(value: DataView | null, offset: number, length: number): string | null {
if (value == null) return null; if (value == null) {
return null;
}
let result = ''; let result = '';
const end = offset + length; const end = offset + length;
@@ -34,14 +38,16 @@ export function decodeString(value: DataView | null, offset: number, length: num
if ((byte1 & 0x80) === 0) { if ((byte1 & 0x80) === 0) {
code = byte1; code = byte1;
} else if ((byte1 & 0xe0) === 0xc0) { }
else if ((byte1 & 0xe0) === 0xc0) {
const byte2 = continuationByte(value, i++, end); const byte2 = continuationByte(value, i++, end);
code = ((byte1 & 0x1f) << 6) | byte2; code = ((byte1 & 0x1f) << 6) | byte2;
if (code < 0x80) { if (code < 0x80) {
throw Error('Invalid continuation byte'); throw Error('Invalid continuation byte');
} }
} else if ((byte1 & 0xf0) === 0xe0) { }
else if ((byte1 & 0xf0) === 0xe0) {
const byte2 = continuationByte(value, i++, end); const byte2 = continuationByte(value, i++, end);
const byte3 = continuationByte(value, i++, end); const byte3 = continuationByte(value, i++, end);
code = ((byte1 & 0x0f) << 12) | (byte2 << 6) | byte3; code = ((byte1 & 0x0f) << 12) | (byte2 << 6) | byte3;
@@ -53,7 +59,8 @@ export function decodeString(value: DataView | null, offset: number, length: num
if (code >= 0xd800 && code <= 0xdfff) { if (code >= 0xd800 && code <= 0xdfff) {
throw Error(`Lone surrogate U+${code.toString(16).toUpperCase()} is not a scalar value`); throw Error(`Lone surrogate U+${code.toString(16).toUpperCase()} is not a scalar value`);
} }
} else if ((byte1 & 0xf8) === 0xf0) { }
else if ((byte1 & 0xf8) === 0xf0) {
const byte2 = continuationByte(value, i++, end); const byte2 = continuationByte(value, i++, end);
const byte3 = continuationByte(value, i++, end); const byte3 = continuationByte(value, i++, end);
const byte4 = continuationByte(value, i++, end); const byte4 = continuationByte(value, i++, end);
@@ -62,7 +69,8 @@ export function decodeString(value: DataView | null, offset: number, length: num
if (code < 0x010000 || code > 0x10ffff) { if (code < 0x010000 || code > 0x10ffff) {
throw Error('Invalid continuation byte'); throw Error('Invalid continuation byte');
} }
} else { }
else {
throw Error('Invalid UTF-8 detected'); throw Error('Invalid UTF-8 detected');
} }
@@ -79,13 +87,16 @@ export function decodeString(value: DataView | null, offset: number, length: num
} }
function continuationByte(buffer: DataView, index: number, end: number): number { function continuationByte(buffer: DataView, index: number, end: number): number {
if (index >= end) throw Error('Invalid byte index'); if (index >= end) {
throw Error('Invalid byte index');
}
const continuationByte = buffer.getUint8(index); const continuationByte = buffer.getUint8(index);
if ((continuationByte & 0xC0) === 0x80) { if ((continuationByte & 0xC0) === 0x80) {
return continuationByte & 0x3F; return continuationByte & 0x3F;
} else { }
else {
throw Error('Invalid continuation byte'); throw Error('Invalid continuation byte');
} }
} }
@@ -99,8 +110,9 @@ export function encodeString(string?: string | null) {
} }
export function getStringLengthWithLength(value?: string | null) { export function getStringLengthWithLength(value?: string | null) {
if (value == null) if (value == null) {
return 1; return 1;
}
const len = stringLengthInBytes(value); const len = stringLengthInBytes(value);
return getLength(len) + len; return getLength(len) + len;
} }
@@ -134,7 +146,8 @@ function forEachCharacter(value: string, callback: (code: number) => void) {
callback(((code & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000); callback(((code & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000);
} }
} }
} else { }
else {
callback(code); callback(code);
} }
} }
@@ -143,11 +156,14 @@ function forEachCharacter(value: string, callback: (code: number) => void) {
function charLengthInBytes(code: number): number { function charLengthInBytes(code: number): number {
if ((code & 0xffffff80) === 0) { if ((code & 0xffffff80) === 0) {
return 1; return 1;
} else if ((code & 0xfffff800) === 0) { }
else if ((code & 0xfffff800) === 0) {
return 2; return 2;
} else if ((code & 0xffff0000) === 0) { }
else if ((code & 0xffff0000) === 0) {
return 3; return 3;
} else { }
else {
return 4; return 4;
} }
} }
+4 -2
View File
@@ -77,7 +77,8 @@ export function canvasToSource(canvas: HTMLCanvasElement) {
canvas.toBlob(blob => { canvas.toBlob(blob => {
if (blob) { if (blob) {
resolve(URL.createObjectURL(blob)); resolve(URL.createObjectURL(blob));
} else { }
else {
reject(new Error('Failed to convert canvas')); reject(new Error('Failed to convert canvas'));
} }
}); });
@@ -93,7 +94,8 @@ export function saveCanvas(canvas: HTMLCanvasElement, name: string) {
export function disableImageSmoothing(context: CanvasRenderingContext2D) { export function disableImageSmoothing(context: CanvasRenderingContext2D) {
if ('imageSmoothingEnabled' in context) { if ('imageSmoothingEnabled' in context) {
context.imageSmoothingEnabled = false; context.imageSmoothingEnabled = false;
} else { }
else {
(context as any).webkitImageSmoothingEnabled = false; (context as any).webkitImageSmoothingEnabled = false;
(context as any).mozImageSmoothingEnabled = false; (context as any).mozImageSmoothingEnabled = false;
(context as any).msImageSmoothingEnabled = false; (context as any).msImageSmoothingEnabled = false;
+48 -22
View File
@@ -68,14 +68,16 @@ function isPonyColliding<T extends Region | undefined>(x: number, y: number, map
function isColliding(x: number, y: number, mask: number, map: IMap<Region | undefined>) { function isColliding(x: number, y: number, mask: number, map: IMap<Region | undefined>) {
if (x < 0 || x >= (map.width * tileWidth) || y < 0 || y >= (map.height * tileHeight)) { if (x < 0 || x >= (map.width * tileWidth) || y < 0 || y >= (map.height * tileHeight)) {
return true; return true;
} else { }
else {
const regionX = (x / REGION_WIDTH) | 0; const regionX = (x / REGION_WIDTH) | 0;
const regionY = (y / REGION_HEIGHT) | 0; const regionY = (y / REGION_HEIGHT) | 0;
const region = map.regions[regionX + regionY * map.regionsX]; const region = map.regions[regionX + regionY * map.regionsX];
if (region === undefined) { if (region === undefined) {
return true; return true;
} else { }
else {
const insideX = (x % REGION_WIDTH) | 0; const insideX = (x % REGION_WIDTH) | 0;
const insideY = (y % REGION_HEIGHT) | 0; const insideY = (y % REGION_HEIGHT) | 0;
return (region.collider[insideX + insideY * REGION_WIDTH] & mask) !== 0; return (region.collider[insideX + insideY * REGION_WIDTH] & mask) !== 0;
@@ -153,24 +155,29 @@ export function updatePosition(entity: Entity, delta: number, map: IMap<Region |
oy = 1; oy = 1;
stepYT = 1 | 0; stepYT = 1 | 0;
stepXF = 1 | 0; stepXF = 1 | 0;
} else { }
else {
ox = 1; ox = 1;
stepYT = -1 | 0; stepYT = -1 | 0;
stepXF = 1 | 0; stepXF = 1 | 0;
} }
} else if (srcX > dstX) { }
else if (srcX > dstX) {
if (srcY < dstY) { if (srcY < dstY) {
oy = 1; oy = 1;
stepYT = 1 | 0; stepYT = 1 | 0;
stepXF = -1 | 0; stepXF = -1 | 0;
} else { }
else {
stepYT = -1 | 0; stepYT = -1 | 0;
stepXF = -1 | 0; stepXF = -1 | 0;
} }
} else { }
else {
if (srcY < dstY) { if (srcY < dstY) {
stepYF = stepYT = 1 | 0; stepYF = stepYT = 1 | 0;
} else { }
else {
stepYF = stepYT = -1 | 0; stepYF = stepYT = -1 | 0;
} }
} }
@@ -187,7 +194,8 @@ export function updatePosition(entity: Entity, delta: number, map: IMap<Region |
if (useGt ? (fx > fy) : (fx < fy)) { if (useGt ? (fx > fy) : (fx < fy)) {
tx = (tx + stepXT) | 0; tx = (tx + stepXT) | 0;
ty = (ty + stepYT) | 0; ty = (ty + stepYT) | 0;
} else { }
else {
tx = (tx + stepXF) | 0; tx = (tx + stepXF) | 0;
ty = (ty + stepYF) | 0; ty = (ty + stepYF) | 0;
} }
@@ -217,7 +225,8 @@ export function updatePosition(entity: Entity, delta: number, map: IMap<Region |
actualNY -= 1; actualNY -= 1;
dstY -= 1; dstY -= 1;
collides = false; collides = false;
} else if ( }
else if (
shiftDown && (canShiftDown = !isColliding(actualX, actualY + 1, mask, map)) && shiftDown && (canShiftDown = !isColliding(actualX, actualY + 1, mask, map)) &&
!isColliding(actualNX, actualY + 1, mask, map) !isColliding(actualNX, actualY + 1, mask, map)
) { ) {
@@ -225,12 +234,14 @@ export function updatePosition(entity: Entity, delta: number, map: IMap<Region |
actualNY += 1; actualNY += 1;
dstY += 1; dstY += 1;
collides = false; collides = false;
} else if (shiftUp && canShiftUp && !isColliding(actualNX, actualY - 2, mask, map)) { }
else if (shiftUp && canShiftUp && !isColliding(actualNX, actualY - 2, mask, map)) {
actualNX = actualX; actualNX = actualX;
actualNY -= 1; actualNY -= 1;
dstY -= 1; dstY -= 1;
collides = false; collides = false;
} else if (shiftDown && canShiftDown && !isColliding(actualNX, actualY + 2, mask, map)) { }
else if (shiftDown && canShiftDown && !isColliding(actualNX, actualY + 2, mask, map)) {
actualNX = actualX; actualNX = actualX;
actualNY += 1; actualNY += 1;
dstY += 1; dstY += 1;
@@ -238,7 +249,8 @@ export function updatePosition(entity: Entity, delta: number, map: IMap<Region |
} }
canMove = canShiftUp || canShiftDown; canMove = canShiftUp || canShiftDown;
} else { }
else {
let canShiftLeft = false; let canShiftLeft = false;
let canShiftRight = false; let canShiftRight = false;
@@ -250,7 +262,8 @@ export function updatePosition(entity: Entity, delta: number, map: IMap<Region |
actualNY = actualY; actualNY = actualY;
dstX -= 1; dstX -= 1;
collides = false; collides = false;
} else if ( }
else if (
shiftRight && (canShiftRight = !isColliding(actualX + 1, actualY, mask, map)) && shiftRight && (canShiftRight = !isColliding(actualX + 1, actualY, mask, map)) &&
!isColliding(actualX + 1, actualNY, mask, map) !isColliding(actualX + 1, actualNY, mask, map)
) { ) {
@@ -258,12 +271,14 @@ export function updatePosition(entity: Entity, delta: number, map: IMap<Region |
actualNY = actualY; actualNY = actualY;
dstX += 1; dstX += 1;
collides = false; collides = false;
} else if (shiftLeft && canShiftLeft && !isColliding(actualX - 2, actualNY, mask, map)) { }
else if (shiftLeft && canShiftLeft && !isColliding(actualX - 2, actualNY, mask, map)) {
actualNX -= 1; actualNX -= 1;
actualNY = actualY; actualNY = actualY;
dstX -= 1; dstX -= 1;
collides = false; collides = false;
} else if (shiftRight && canShiftRight && !isColliding(actualX + 2, actualNY, mask, map)) { }
else if (shiftRight && canShiftRight && !isColliding(actualX + 2, actualNY, mask, map)) {
actualNX += 1; actualNX += 1;
actualNY = actualY; actualNY = actualY;
dstX += 1; dstX += 1;
@@ -277,7 +292,8 @@ export function updatePosition(entity: Entity, delta: number, map: IMap<Region |
if (!collides) { if (!collides) {
actualX = actualNX; actualX = actualNX;
actualY = actualNY; actualY = actualNY;
} else if (!canMove || horizontalOrVertical) { }
else if (!canMove || horizontalOrVertical) {
break; break;
} }
} }
@@ -301,17 +317,27 @@ export function setColliderDirty(map: IMap<Region | undefined>, region: Region,
if (x === 0) { if (x === 0) {
const r = getRegionUnsafe(map, region.x - 1, region.y); const r = getRegionUnsafe(map, region.x - 1, region.y);
r && (r.colliderDirty = true); if (r) {
} else if (x === (REGION_SIZE - 1)) { (r.colliderDirty = true);
}
}
else if (x === (REGION_SIZE - 1)) {
const r = getRegionUnsafe(map, region.x + 1, region.y); const r = getRegionUnsafe(map, region.x + 1, region.y);
r && (r.colliderDirty = true); if (r) {
(r.colliderDirty = true);
}
} }
if (y === 0) { if (y === 0) {
const r = getRegionUnsafe(map, region.x, region.y - 1); const r = getRegionUnsafe(map, region.x, region.y - 1);
r && (r.colliderDirty = true); if (r) {
} else if (y === (REGION_SIZE - 1)) { (r.colliderDirty = true);
}
}
else if (y === (REGION_SIZE - 1)) {
const r = getRegionUnsafe(map, region.x, region.y + 1); const r = getRegionUnsafe(map, region.x, region.y + 1);
r && (r.colliderDirty = true); if (r) {
(r.colliderDirty = true);
}
} }
} }
+36 -14
View File
@@ -217,7 +217,8 @@ export function colorToCSS(color: number): string {
if (alpha === 0xff) { if (alpha === 0xff) {
return `#${colorToHexRGB(color)}`; return `#${colorToHexRGB(color)}`;
} else { }
else {
return `rgba(${getR(color)},${getG(color)},${getB(color)},${alpha / 255})`; return `rgba(${getR(color)},${getG(color)},${getB(color)},${alpha / 255})`;
} }
} }
@@ -277,26 +278,30 @@ export function colorFromHSVAObject({ h, s, v, a }: HSVA) {
// parse // parse
export function parseColorFast(str: string): number { export function parseColorFast(str: string): number {
if (!isString(str)) if (!isString(str)) {
return TRANSPARENT; return TRANSPARENT;
}
const int = parseInt(str, 16); const int = parseInt(str, 16);
if (str.length !== 6 || isNaN(int) || int < 0) { if (str.length !== 6 || isNaN(int) || int < 0) {
return parseColorWithAlpha(str, 1); return parseColorWithAlpha(str, 1);
} else { }
else {
return (((int << 8) | 0xff) >>> 0); return (((int << 8) | 0xff) >>> 0);
} }
} }
export function parseColor(str: string): number { export function parseColor(str: string): number {
if (!isString(str)) if (!isString(str)) {
return TRANSPARENT; return TRANSPARENT;
}
str = str.trim().toLowerCase(); str = str.trim().toLowerCase();
if (str === '' || str === 'none' || str === 'transparent') if (str === '' || str === 'none' || str === 'transparent') {
return TRANSPARENT; return TRANSPARENT;
}
str = colorNames[str] || str; str = colorNames[str] || str;
@@ -320,7 +325,8 @@ export function parseColor(str: string): number {
parseInt(s.charAt(0), 16) * 0x11, parseInt(s.charAt(0), 16) * 0x11,
parseInt(s.charAt(1), 16) * 0x11, parseInt(s.charAt(1), 16) * 0x11,
parseInt(s.charAt(2), 16) * 0x11, 255); parseInt(s.charAt(2), 16) * 0x11, 255);
} else { }
else {
return colorFromRGBA( return colorFromRGBA(
parseInt(s.substr(0, 2), 16), parseInt(s.substr(0, 2), 16),
parseInt(s.substr(2, 2), 16), parseInt(s.substr(2, 2), 16),
@@ -511,18 +517,34 @@ export function rgb2hsl(rgb: RGB): HSL {
let s; let s;
let l; let l;
if (max === min) h = 0; if (max === min) {
else if (r === max) h = (g - b) / delta; h = 0;
else if (g === max) h = 2 + (b - r) / delta; }
else if (b === max) h = 4 + (r - g) / delta; else if (r === max) {
h = (g - b) / delta;
}
else if (g === max) {
h = 2 + (b - r) / delta;
}
else if (b === max) {
h = 4 + (r - g) / delta;
}
h = Math.min(h * 60, 360); h = Math.min(h * 60, 360);
if (h < 0) h += 360; if (h < 0) {
h += 360;
}
l = (min + max) / 2; l = (min + max) / 2;
if (max === min) s = 0; if (max === min) {
else if (l <= 0.5) s = delta / (max + min); s = 0;
else s = delta / (2 - max - min); }
else if (l <= 0.5) {
s = delta / (max + min);
}
else {
s = delta / (2 - max - min);
}
h = Math.floor(h); h = Math.floor(h);
s = Math.floor(s * 100); s = Math.floor(s * 100);
l = Math.floor(l * 100); l = Math.floor(l * 100);
+10 -5
View File
@@ -123,7 +123,8 @@ export function blushColor(coat: number): number {
(h > 280 && s > 0.2 && s < 0.7 && v > 0.85) (h > 280 && s > 0.2 && s < 0.7 && v > 0.85)
) { ) {
return DARK_BLUSH; return DARK_BLUSH;
} else { }
else {
return LIGHT_BLUSH; return LIGHT_BLUSH;
} }
} }
@@ -134,9 +135,11 @@ export function getTileColor(tile: TileType, season: Season) {
case TileType.ElevatedDirt: case TileType.ElevatedDirt:
if (season === Season.Autumn) { if (season === Season.Autumn) {
return 0xedd29eff; return 0xedd29eff;
} else if (season === Season.Winter) { }
else if (season === Season.Winter) {
return 0xd9c2a1ff; return 0xd9c2a1ff;
} else { }
else {
return 0xf5d99bff; return 0xf5d99bff;
} }
case TileType.Water: case TileType.Water:
@@ -146,9 +149,11 @@ export function getTileColor(tile: TileType, season: Season) {
case TileType.Grass: case TileType.Grass:
if (season === Season.Autumn) { if (season === Season.Autumn) {
return 0xddcf71ff; return 0xddcf71ff;
} else if (season === Season.Winter) { }
else if (season === Season.Winter) {
return 0xe1ebf8ff; return 0xe1ebf8ff;
} else { }
else {
return 0x7cc991ff; return 0x7cc991ff;
} }
case TileType.Ice: case TileType.Ice:
+12 -6
View File
@@ -43,7 +43,8 @@ export function compressTiles(tiles: Uint8Array): Uint8Array {
if (i === (tiles.length - 1)) { if (i === (tiles.length - 1)) {
write(count | 0b1000, bitsPerRun); write(count | 0b1000, bitsPerRun);
write(types.indexOf(value), bitsPerTile); write(types.indexOf(value), bitsPerTile);
} else { }
else {
i++; i++;
if (value === tiles[i]) { if (value === tiles[i]) {
@@ -56,7 +57,8 @@ export function compressTiles(tiles: Uint8Array): Uint8Array {
write(count, bitsPerRun); write(count, bitsPerRun);
write(types.indexOf(value), bitsPerTile); write(types.indexOf(value), bitsPerTile);
} else { }
else {
let last = tiles[i]; let last = tiles[i];
let last2 = last; let last2 = last;
let pushLast = true; let pushLast = true;
@@ -71,10 +73,12 @@ export function compressTiles(tiles: Uint8Array): Uint8Array {
count--; count--;
pushLast = false; pushLast = false;
break; break;
} else if (count === 0b111) { }
else if (count === 0b111) {
i -= 1; i -= 1;
break; break;
} else { }
else {
values.push(last); values.push(last);
count++; count++;
last = last2; last = last2;
@@ -110,7 +114,8 @@ export function decompressTiles(data: Uint8Array): Uint8Array {
if (types.length === 1) { if (types.length === 1) {
result.fill(types[0]); result.fill(types[0]);
} else { }
else {
const bitsPerTile = getBitsForNumber(typesCount); const bitsPerTile = getBitsForNumber(typesCount);
const bitsPerRun = 4; const bitsPerRun = 4;
@@ -125,7 +130,8 @@ export function decompressTiles(data: Uint8Array): Uint8Array {
result[i] = types[entry]; result[i] = types[entry];
i++; i++;
} }
} else { }
else {
const count = value & 0b0111; const count = value & 0b0111;
for (let j = 0; j < count; j++) { for (let j = 0; j < count; j++) {
+10 -5
View File
@@ -307,13 +307,15 @@ const ALL_LOCKED = array(MAX_COLORS, true);
export function precompressSet<T>( export function precompressSet<T>(
set: SpriteSet<T> | undefined, def: SetDefinition, customOutlines: boolean, defaultColor: T, addColor: (color: T) => number set: SpriteSet<T> | undefined, def: SetDefinition, customOutlines: boolean, defaultColor: T, addColor: (color: T) => number
): PrecompressedSet | undefined { ): PrecompressedSet | undefined {
if (!set) if (!set) {
return undefined; return undefined;
}
const type = clamp(toInt(set.type), 0, def.sets.length - 1); const type = clamp(toInt(set.type), 0, def.sets.length - 1);
if (type === 0 && !def.preserveOnZero) if (type === 0 && !def.preserveOnZero) {
return undefined; return undefined;
}
const patterns = at(def.sets, type); const patterns = at(def.sets, type);
const pattern = clamp(toInt(set.pattern), 0, patterns ? patterns.length - 1 : 0); const pattern = clamp(toInt(set.pattern), 0, patterns ? patterns.length - 1 : 0);
@@ -321,8 +323,9 @@ export function precompressSet<T>(
const colors = Math.max(getColorCount(sprite), def.minColors || 0); const colors = Math.max(getColorCount(sprite), def.minColors || 0);
/* istanbul ignore next */ /* istanbul ignore next */
if (type === 0 && pattern === 0 && colors === 0) if (type === 0 && pattern === 0 && colors === 0) {
return undefined; return undefined;
}
const fillLocks = compressLockSet(set.lockFills, colors); const fillLocks = compressLockSet(set.lockFills, colors);
const fills = precompressColorSet(set.fills, colors, fillLocks, defaultColor, addColor); const fills = precompressColorSet(set.fills, colors, fillLocks, defaultColor, addColor);
@@ -355,7 +358,8 @@ function precompressFields<TDef extends FieldDefinition<TResult>, TValue, TResul
return trimRight(defs.map(def => { return trimRight(defs.map(def => {
if (def.dontSave || (def.omit && def.omit(data))) { if (def.dontSave || (def.omit && def.omit(data))) {
return defaultValue; return defaultValue;
} else { }
else {
return encode(data[def.name], def); return encode(data[def.name], def);
} }
})); }));
@@ -512,7 +516,8 @@ export function readSet(
const outlineLocks = customOutlines ? read(colors) : 0; const outlineLocks = customOutlines ? read(colors) : 0;
const outlines = customOutlines ? readTimes(read, colors - countBits(outlineLocks), colorBits) : []; const outlines = customOutlines ? readTimes(read, colors - countBits(outlineLocks), colorBits) : [];
return { type, pattern, colors, fillLocks, fills, outlineLocks, outlines }; return { type, pattern, colors, fillLocks, fills, outlineLocks, outlines };
} else { }
else {
return undefined; return undefined;
} }
} }
+4 -2
View File
@@ -4,8 +4,9 @@ import { hasFlag } from '../utils';
export const EMPTY_EXPRESSION = 0x1fffffff; export const EMPTY_EXPRESSION = 0x1fffffff;
export function encodeExpression(expression: Expression | undefined): number { export function encodeExpression(expression: Expression | undefined): number {
if (!expression) if (!expression) {
return EMPTY_EXPRESSION; return EMPTY_EXPRESSION;
}
const { extra, rightIris, leftIris, right, left, muzzle } = expression; const { extra, rightIris, leftIris, right, left, muzzle } = expression;
@@ -16,8 +17,9 @@ export function encodeExpression(expression: Expression | undefined): number {
export function decodeExpression(value: number): Expression | undefined { export function decodeExpression(value: number): Expression | undefined {
value = value >>> 0; value = value >>> 0;
if (value === EMPTY_EXPRESSION) if (value === EMPTY_EXPRESSION) {
return undefined; return undefined;
}
const muzzle = value & 0x1f; const muzzle = value & 0x1f;
const left = (value >> 5) & 0x1f; const left = (value >> 5) & 0x1f;
+2 -1
View File
@@ -90,8 +90,9 @@ export function decodeUpdate(data: Uint8Array): DecodedRegionUpdate {
} }
export function readOneUpdate(reader: BinaryReader): DecodedUpdate | undefined { export function readOneUpdate(reader: BinaryReader): DecodedUpdate | undefined {
if (reader.offset >= reader.view.byteLength) if (reader.offset >= reader.view.byteLength) {
return undefined; return undefined;
}
const flags = readUint16(reader); const flags = readUint16(reader);
+2 -1
View File
@@ -42,8 +42,9 @@ if (DEVELOPMENT) {
} }
for (const { type } of entities) { for (const { type } of entities) {
if (type === 0) if (type === 0) {
continue; continue;
}
const entity = createAnEntity(type, 0, 0, 0, {}, mockPaletteManager, defaultWorldState); const entity = createAnEntity(type, 0, 0, 0, {}, mockPaletteManager, defaultWorldState);
const name = getEntityTypeName(type); const name = getEntityTypeName(type);
+5 -2
View File
@@ -134,7 +134,8 @@ export function mixBounds(x: number, y: number, w: number, h: number): MixinEnti
export function mixServerFlags(flags: ServerFlags): MixinEntity { export function mixServerFlags(flags: ServerFlags): MixinEntity {
if (SERVER) { if (SERVER) {
return base => base.serverFlags! |= flags; return base => base.serverFlags! |= flags;
} else { }
else {
return () => { }; return () => { };
} }
} }
@@ -180,7 +181,9 @@ export function doodadSet(name: string, sprite: PaletteRenderable, ox: number, o
// placeholder entity // placeholder entity
registerMix(n('null'), () => { throw new Error('Invalid type (0)'); }); registerMix(n('null'), () => {
throw new Error('Invalid type (0)');
});
// entities // entities
+6 -3
View File
@@ -53,9 +53,11 @@ export function getPonyChatHeight(pony: Pony) {
if (pony.animator.state === trotting) { if (pony.animator.state === trotting) {
return baseHeight; return baseHeight;
} else if (pony.animator.state === flying || pony.animator.state === hovering) { }
else if (pony.animator.state === flying || pony.animator.state === hovering) {
return baseHeight - 16; return baseHeight - 16;
} else { }
else {
const frame = getPonyAnimationFrame(state.animation, state.animationFrame, defaultBodyFrame); const frame = getPonyAnimationFrame(state.animation, state.animationFrame, defaultBodyFrame);
const animation = state.headAnimation || defaultHeadAnimation; const animation = state.headAnimation || defaultHeadAnimation;
const headFrame = getPonyAnimationFrame(animation, state.headAnimationFrame, defaultHeadFrame); const headFrame = getPonyAnimationFrame(animation, state.headAnimationFrame, defaultHeadFrame);
@@ -284,7 +286,8 @@ export function addOrRemoveFromEntityList(list: Entity[], entity: Entity, had: b
if (had !== has) { if (had !== has) {
if (has) { if (has) {
pushUniq(list, entity); pushUniq(list, entity);
} else { }
else {
removeItemFast(list, entity); removeItemFast(list, entity);
} }
} }
+10 -5
View File
@@ -180,13 +180,15 @@ const horizontalRegex = new RegExp(`^${any(horizontalEyesRight)}(//)?${any(horiz
function matchVertical( function matchVertical(
text: string, regex: RegExp, flip: boolean, muzzleMap: Dict<Muzzle>, eyesMap: Dict<Eye>, command: boolean = false text: string, regex: RegExp, flip: boolean, muzzleMap: Dict<Muzzle>, eyesMap: Dict<Eye>, command: boolean = false
): Expression | undefined { ): Expression | undefined {
if (!command && /^([|]{2,}|BS|8x|x8|x-?x|\d+)$/i.test(text)) if (!command && /^([|]{2,}|BS|8x|x8|x-?x|\d+)$/i.test(text)) {
return undefined; return undefined;
}
const match = regex.exec(text); const match = regex.exec(text);
if (!match) if (!match) {
return undefined; return undefined;
}
const eyesStr = flip ? match[3] : match[1]; const eyesStr = flip ? match[3] : match[1];
const muzzleStr = flip ? match[1] : match[3]; const muzzleStr = flip ? match[1] : match[3];
@@ -288,11 +290,14 @@ const constants = createPlainMap<() => Expression | undefined>({
function matchOther(text: string): Expression | undefined { function matchOther(text: string): Expression | undefined {
if (/^A{5,}\.*$/.test(text)) { if (/^A{5,}\.*$/.test(text)) {
return expression(Eye.Neutral, Eye.Neutral, Muzzle.ConcernedOpen3, Iris.Shocked, Iris.Shocked); return expression(Eye.Neutral, Eye.Neutral, Muzzle.ConcernedOpen3, Iris.Shocked, Iris.Shocked);
} else if (/^a{5,}\.*$/.test(text)) { }
else if (/^a{5,}\.*$/.test(text)) {
return expression(Eye.Neutral, Eye.Neutral, Muzzle.ConcernedOpen3); return expression(Eye.Neutral, Eye.Neutral, Muzzle.ConcernedOpen3);
} else if (/^z{3,}\.*$/i.test(text)) { }
else if (/^z{3,}\.*$/i.test(text)) {
return expression(Eye.Closed, Eye.Closed, Muzzle.Neutral); return expression(Eye.Closed, Eye.Closed, Muzzle.Neutral);
} else { }
else {
return constants[text] && constants[text](); return constants[text] && constants[text]();
} }
} }
+2 -1
View File
@@ -14,7 +14,8 @@ export const urlRegexTexts = [
export function trimRepeatedLetters(test: string): string { export function trimRepeatedLetters(test: string): string {
if (test.length > MAX_REPEATS && (/^.?(.)\1+$/u.test(test) || /^.?(..)\1+$/u.test(test))) { if (test.length > MAX_REPEATS && (/^.?(.)\1+$/u.test(test) || /^.?(..)\1+$/u.test(test))) {
return test.substr(0, MAX_REPEATS) + '…'; return test.substr(0, MAX_REPEATS) + '…';
} else { }
else {
return test; return test;
} }
} }
+9 -7
View File
@@ -144,7 +144,9 @@ export const enum EntityState {
Editable = 8, Editable = 8,
// pony // pony
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
HeadTurned = 4, HeadTurned = 4,
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
Magic = 8, Magic = 8,
// CanFly ?, // Or in flags ? // CanFly ?, // Or in flags ?
@@ -203,7 +205,8 @@ export const enum MessageType {
export function toMessageType(type: MessageType) { export function toMessageType(type: MessageType) {
if (type === MessageType.WhisperAnnouncement) { if (type === MessageType.WhisperAnnouncement) {
return MessageType.WhisperToAnnouncement; return MessageType.WhisperToAnnouncement;
} else { }
else {
return MessageType.WhisperTo; return MessageType.WhisperTo;
} }
} }
@@ -1274,11 +1277,9 @@ export interface PalettePonyInfo extends PonyInfoBase<Palette, PaletteSpriteSet>
magicColorValue: number; magicColorValue: number;
} }
export interface PonyInfo extends PonyInfoBase<string, SpriteSet<string>> { export type PonyInfo = PonyInfoBase<string, SpriteSet<string>>;
}
export interface PonyInfoNumber extends PonyInfoBase<number, SpriteSet<number>> { export type PonyInfoNumber = PonyInfoBase<number, SpriteSet<number>>;
}
export interface ColorExtra { export interface ColorExtra {
color: Sprite; color: Sprite;
@@ -1742,7 +1743,7 @@ export interface EntityDescriptor {
create: CreateEntity; create: CreateEntity;
} }
export type EntityOptions = PonyEntityOptions | SpiderEntityOptions | SignEntityOptions | {}; export type EntityOptions = PonyEntityOptions | SpiderEntityOptions | SignEntityOptions | object;
export type EntityOrPonyOptions = Partial<PonyOptions> & EntityOptions; export type EntityOrPonyOptions = Partial<PonyOptions> & EntityOptions;
export interface EntityWorldState { export interface EntityWorldState {
@@ -1826,7 +1827,8 @@ export let counterNow: () => number;
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
counterNow = performance.now; counterNow = performance.now;
} else { }
else {
const hrtime = process.hrtime; const hrtime = process.hrtime;
const getNanoSeconds = () => { const getNanoSeconds = () => {
const hr = hrtime(); const hr = hrtime();
+2 -1
View File
@@ -102,7 +102,8 @@ export function skewTransform(base: Matrix2D | undefined, skew: number, ox: numb
translateMat2D(tempMatrix, tempMatrix, ox + x, oy + y); translateMat2D(tempMatrix, tempMatrix, ox + x, oy + y);
skewY(tempMatrix, tempMatrix, skew); skewY(tempMatrix, tempMatrix, skew);
translateMat2D(tempMatrix, tempMatrix, -ox, -oy); translateMat2D(tempMatrix, tempMatrix, -ox, -oy);
} else { }
else {
translateMat2D(tempMatrix, tempMatrix, x, y); translateMat2D(tempMatrix, tempMatrix, x, y);
} }
+90 -34
View File
@@ -50,11 +50,14 @@ function getBounds(sprite: Sprite | undefined, ox: number, oy: number): Rect {
export function getRenderableBounds({ color, shadow }: Renderable, dx: number, dy: number): Rect { export function getRenderableBounds({ color, shadow }: Renderable, dx: number, dy: number): Rect {
if (color && shadow) { if (color && shadow) {
return addRects(getBounds(color, -dx, -dy), getBounds(shadow, -dx, -dy)); return addRects(getBounds(color, -dx, -dy), getBounds(shadow, -dx, -dy));
} else if (color) { }
else if (color) {
return getBounds(color, -dx, -dy); return getBounds(color, -dx, -dy);
} else if (shadow) { }
else if (shadow) {
return getBounds(shadow, -dx, -dy); return getBounds(shadow, -dx, -dy);
} else { }
else {
return rect(0, 0, 0, 0); return rect(0, 0, 0, 0);
} }
} }
@@ -288,15 +291,20 @@ export function mixAnimation(
} }
return at(animations[animation], frameNumber) || 0; return at(animations[animation], frameNumber) || 0;
} else { }
else {
return repeat ? (frameNumber % anim.frames.length) : Math.min(frameNumber, anim.frames.length - 1); return repeat ? (frameNumber % anim.frames.length) : Math.min(frameNumber, anim.frames.length - 1);
} }
}; };
base.bounds = bounds; base.bounds = bounds;
base.palettes = []; base.palettes = [];
defaultPalette && base.palettes.push(defaultPalette); if (defaultPalette) {
palette && base.palettes.push(palette); base.palettes.push(defaultPalette);
}
if (palette) {
base.palettes.push(palette);
}
base.update = function (delta: number) { base.update = function (delta: number) {
time += delta; time += delta;
@@ -313,7 +321,8 @@ export function mixAnimation(
if (lastFrame !== frameNumber) { if (lastFrame !== frameNumber) {
lastFrame = frameNumber; lastFrame = frameNumber;
return true; return true;
} else { }
else {
return false; return false;
} }
}; };
@@ -332,8 +341,12 @@ export function mixAnimation(
} }
batch.translate(-dx, -dy); batch.translate(-dx, -dy);
anim.shadow && batch.drawSprite(anim.shadow, options.shadowColor, defaultPalette, 0, 0); if (anim.shadow) {
frameSprite && batch.drawSprite(frameSprite, color, palette, 0, 0); batch.drawSprite(anim.shadow, options.shadowColor, defaultPalette, 0, 0);
}
if (frameSprite) {
batch.drawSprite(frameSprite, color, palette, 0, 0);
}
batch.restore(); batch.restore();
}; };
@@ -374,8 +387,12 @@ export function mixDrawWindow(
const defaultPalette = sprite.shadow && createPalette(sprites.defaultPalette); const defaultPalette = sprite.shadow && createPalette(sprites.defaultPalette);
const palette = createPalette(att(sprite.palettes, paletteIndex)); const palette = createPalette(att(sprite.palettes, paletteIndex));
base.palettes = []; base.palettes = [];
defaultPalette && base.palettes.push(defaultPalette); if (defaultPalette) {
palette && base.palettes.push(palette); base.palettes.push(defaultPalette);
}
if (palette) {
base.palettes.push(palette);
}
base.draw = function (batch, options) { base.draw = function (batch, options) {
const baseX = toScreenX(this.x + (this.ox || 0)); const baseX = toScreenX(this.x + (this.ox || 0));
@@ -407,8 +424,12 @@ export function mixDraw(sprite: PaletteRenderable, dx: number, dy: number, palet
const defaultPalette = sprite.shadow && createPalette(sprites.defaultPalette); const defaultPalette = sprite.shadow && createPalette(sprites.defaultPalette);
const palette = createPalette(att(sprite.palettes, paletteIndex)); const palette = createPalette(att(sprite.palettes, paletteIndex));
base.palettes = []; base.palettes = [];
defaultPalette && base.palettes.push(defaultPalette); if (defaultPalette) {
palette && base.palettes.push(palette); base.palettes.push(defaultPalette);
}
if (palette) {
base.palettes.push(palette);
}
base.draw = function (batch: PaletteSpriteBatch, options: DrawOptions) { base.draw = function (batch: PaletteSpriteBatch, options: DrawOptions) {
const x = toScreenX(this.x + (this.ox || 0)) - dx; const x = toScreenX(this.x + (this.ox || 0)) - dx;
@@ -506,8 +527,12 @@ export function mixDrawSeasonal(setup: MixDrawSeasonal): MixinEntity {
defaultPalette = sprite.shadow && createPalette(sprites.defaultPalette); defaultPalette = sprite.shadow && createPalette(sprites.defaultPalette);
palette = createPalette(att(sprite.palettes, paletteIndex)); palette = createPalette(att(sprite.palettes, paletteIndex));
base.palettes = []; base.palettes = [];
defaultPalette && base.palettes.push(defaultPalette); if (defaultPalette) {
palette && base.palettes.push(palette); base.palettes.push(defaultPalette);
}
if (palette) {
base.palettes.push(palette);
}
}; };
setupSeason(worldState.season); setupSeason(worldState.season);
@@ -597,8 +622,9 @@ export function mixDrawDirectionSign(): MixinEntity {
base.bounds = rect(-20, -boundsH, 40, boundsH); base.bounds = rect(-20, -boundsH, 40, boundsH);
base.options = options; base.options = options;
if (SERVER && !TESTS) if (SERVER && !TESTS) {
return; return;
}
const { const {
shadowUp, shadowDown, spriteUp, spriteDown, upDX, upDY, downDX, downDY, shadowUp, shadowDown, spriteUp, spriteDown, upDX, upDY, downDX, downDY,
@@ -613,18 +639,30 @@ export function mixDrawDirectionSign(): MixinEntity {
const defaultPalette = pole.sprite.shadow && createPalette(sprites.defaultPalette); const defaultPalette = pole.sprite.shadow && createPalette(sprites.defaultPalette);
const palette = createPalette(att(pole.sprite.palettes, 0)); const palette = createPalette(att(pole.sprite.palettes, 0));
base.palettes = []; base.palettes = [];
defaultPalette && base.palettes.push(defaultPalette); if (defaultPalette) {
palette && base.palettes.push(palette); base.palettes.push(defaultPalette);
}
if (palette) {
base.palettes.push(palette);
}
base.draw = function (batch, options) { base.draw = function (batch, options) {
const x = toScreenX(this.x); const x = toScreenX(this.x);
const y = toScreenYWithZ(this.y, this.z); const y = toScreenYWithZ(this.y, this.z);
batch.drawSprite(pole.sprite.shadow, options.shadowColor, defaultPalette, x + poleDX, y + pole.dy); batch.drawSprite(pole.sprite.shadow, options.shadowColor, defaultPalette, x + poleDX, y + pole.dy);
leftShadow && batch.drawSprite(shadowLeft, options.shadowColor, defaultPalette, x - 18, y - 1); if (leftShadow) {
rightShadow && batch.drawSprite(shadowRight, options.shadowColor, defaultPalette, x + 4, y - 1); batch.drawSprite(shadowLeft, options.shadowColor, defaultPalette, x - 18, y - 1);
upShadow && batch.drawSprite(shadowUp, options.shadowColor, defaultPalette, x + shadowUpDX, y + shadowUpDY); }
downShadow && batch.drawSprite(shadowDown, options.shadowColor, defaultPalette, x + shadowDownDX, y + shadowDownDY); if (rightShadow) {
batch.drawSprite(shadowRight, options.shadowColor, defaultPalette, x + 4, y - 1);
}
if (upShadow) {
batch.drawSprite(shadowUp, options.shadowColor, defaultPalette, x + shadowUpDX, y + shadowUpDY);
}
if (downShadow) {
batch.drawSprite(shadowDown, options.shadowColor, defaultPalette, x + shadowDownDX, y + shadowDownDY);
}
for (let i = n.length - 1; i >= 0; i--) { for (let i = n.length - 1; i >= 0; i--) {
if (n[i] !== -1) { if (n[i] !== -1) {
@@ -637,14 +675,18 @@ export function mixDrawDirectionSign(): MixinEntity {
for (let i = 0; i < w.length; i++) { for (let i = 0; i < w.length; i++) {
if (w[i] !== -1) { if (w[i] !== -1) {
const sprite = leftSprites[w[i]]; const sprite = leftSprites[w[i]];
sprite && batch.drawSprite(sprite, WHITE, palette, x + leftDX, y + pole.dy + plateDY + i * leftRightStep); if (sprite) {
batch.drawSprite(sprite, WHITE, palette, x + leftDX, y + pole.dy + plateDY + i * leftRightStep);
}
} }
} }
for (let i = 0; i < e.length; i++) { for (let i = 0; i < e.length; i++) {
if (e[i] !== -1) { if (e[i] !== -1) {
const sprite = rightSprites[e[i]]; const sprite = rightSprites[e[i]];
sprite && batch.drawSprite(rightSprites[e[i]], WHITE, palette, x + rightDX, y + pole.dy + plateDY + i * leftRightStep); if (sprite) {
batch.drawSprite(rightSprites[e[i]], WHITE, palette, x + rightDX, y + pole.dy + plateDY + i * leftRightStep);
}
} }
} }
@@ -668,8 +710,9 @@ export function mixLight(color: number, dx: number, dy: number, w: number, h: nu
const adjustedScale = base.lightScale * base.lightScaleAdjust * LIGHT_VOLUME_SCALE; const adjustedScale = base.lightScale * base.lightScaleAdjust * LIGHT_VOLUME_SCALE;
base.lightBounds = rect(-(dx + w / 2), -(dy + h / 2), w * adjustedScale, h * adjustedScale); base.lightBounds = rect(-(dx + w / 2), -(dy + h / 2), w * adjustedScale, h * adjustedScale);
base.drawLight = function (batch: SpriteBatch) { base.drawLight = function (batch: SpriteBatch) {
if (!this.lightOn) if (!this.lightOn) {
return; return;
}
const x = toScreenX(this.x); const x = toScreenX(this.x);
const y = toScreenYWithZ(this.y, this.z); const y = toScreenYWithZ(this.y, this.z);
@@ -692,8 +735,9 @@ export function mixLightSprite(sprite: Sprite, color: number, dx: number, dy: nu
base.lightSpriteColor = color; base.lightSpriteColor = color;
base.lightSpriteBounds = getBounds(sprite, -dx, -dy); base.lightSpriteBounds = getBounds(sprite, -dx, -dy);
base.drawLightSprite = function (batch: SpriteBatch) { base.drawLightSprite = function (batch: SpriteBatch) {
if (!this.lightSpriteOn) if (!this.lightSpriteOn) {
return; return;
}
const x = toScreenX(this.x) - this.lightSpriteX!; const x = toScreenX(this.x) - this.lightSpriteX!;
const y = toScreenYWithZ(this.y, this.z) - this.lightSpriteY!; const y = toScreenYWithZ(this.y, this.z) - this.lightSpriteY!;
@@ -711,8 +755,9 @@ export function mixDrawRain(): MixinEntity {
return base => { return base => {
base.bounds = bounds; base.bounds = bounds;
if (SERVER && !TESTS) if (SERVER && !TESTS) {
return; return;
}
let time = 0; let time = 0;
const palette = createPalette(sprites.defaultPalette); const palette = createPalette(sprites.defaultPalette);
@@ -747,7 +792,9 @@ export function mixDrawShadow(sprite: PaletteRenderable, dx: number, dy: number,
const x = toScreenX(this.x + (this.ox || 0)) - dx; const x = toScreenX(this.x + (this.ox || 0)) - dx;
const y = toScreenYWithZ(this.y + (this.oy || 0), this.z) - dy; const y = toScreenYWithZ(this.y + (this.oy || 0), this.z) - dy;
const color = shadowColor === undefined ? options.shadowColor : shadowColor; const color = shadowColor === undefined ? options.shadowColor : shadowColor;
sprite.shadow && batch.drawSprite(sprite.shadow, color, defaultPalette, x, y); if (sprite.shadow) {
batch.drawSprite(sprite.shadow, color, defaultPalette, x, y);
}
}; };
} }
}; };
@@ -776,22 +823,29 @@ export function mixDrawWall(
return base => { return base => {
base.bounds = fullBounds; // fullWalls ? fullBounds : halfBounds base.bounds = fullBounds; // fullWalls ? fullBounds : halfBounds
if (SERVER && !TESTS) if (SERVER && !TESTS) {
return; return;
}
const fullPalette = createPalette(att(full.palettes, 0)); const fullPalette = createPalette(att(full.palettes, 0));
const halfPalette = createPalette(att(half.palettes, 0)); const halfPalette = createPalette(att(half.palettes, 0));
base.palettes = []; base.palettes = [];
fullPalette && base.palettes.push(fullPalette); if (fullPalette) {
halfPalette && base.palettes.push(halfPalette); base.palettes.push(fullPalette);
}
if (halfPalette) {
base.palettes.push(halfPalette);
}
base.draw = function (batch: PaletteSpriteBatch) { base.draw = function (batch: PaletteSpriteBatch) {
const sprite = fullWalls ? full : half; const sprite = fullWalls ? full : half;
const palette = fullWalls ? fullPalette : halfPalette; const palette = fullWalls ? fullPalette : halfPalette;
const x = toScreenX(this.x) - dx; const x = toScreenX(this.x) - dx;
const y = toScreenYWithZ(this.y, this.z) - (fullWalls ? dy : dy2); const y = toScreenYWithZ(this.y, this.z) - (fullWalls ? dy : dy2);
sprite.color && batch.drawSprite(sprite.color, WHITE, palette, x, y); if (sprite.color) {
batch.drawSprite(sprite.color, WHITE, palette, x, y);
}
}; };
}; };
} }
@@ -803,8 +857,9 @@ export function mixDrawSpider(
const spriteColor = sprite.color; const spriteColor = sprite.color;
const baseBounds = getRenderableBounds(sprite, dx, dy); const baseBounds = getRenderableBounds(sprite, dx, dy);
if (!spriteColor) if (!spriteColor) {
throw new Error('Missing sprite'); throw new Error('Missing sprite');
}
return base => { return base => {
const { height, time } = base.options as { height: number; time: number; }; const { height, time } = base.options as { height: number; time: number; };
@@ -813,8 +868,9 @@ export function mixDrawSpider(
bounds.h += height; bounds.h += height;
base.bounds = bounds; base.bounds = bounds;
if (SERVER && !TESTS) if (SERVER && !TESTS) {
return; return;
}
const palette = createPalette(sprite.palettes && sprite.palettes[0]); const palette = createPalette(sprite.palettes && sprite.palettes[0]);
base.palettes = [palette]; base.palettes = [palette];
+4 -2
View File
@@ -36,9 +36,11 @@ export function flagsToSpeed(flags: EntityState): number {
if (state === EntityState.PonyTrotting) { if (state === EntityState.PonyTrotting) {
return PONY_SPEED_TROT; return PONY_SPEED_TROT;
} else if (state === EntityState.PonyWalking) { }
else if (state === EntityState.PonyWalking) {
return PONY_SPEED_WALK; return PONY_SPEED_WALK;
} else { }
else {
return 0; return 0;
} }
} }
+1
View File
@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import { BodyAnimation, BodyAnimationFrame, HeadAnimation, HeadAnimationFrame, BodyShadow, HeadAnimationProperties } from './interfaces'; import { BodyAnimation, BodyAnimationFrame, HeadAnimation, HeadAnimationFrame, BodyShadow, HeadAnimationProperties } from './interfaces';
import { repeat, flatten } from './utils'; import { repeat, flatten } from './utils';
+18 -9
View File
@@ -37,8 +37,9 @@ export const mockPaletteManager: PaletteManager = {
}; };
export function spriteSet(type: number, lockFirstFill = true, fill = 'ffd700', otherFills = FILLS): SpriteSet<string> { export function spriteSet(type: number, lockFirstFill = true, fill = 'ffd700', otherFills = FILLS): SpriteSet<string> {
if (otherFills.length !== (MAX_COLORS - 1)) if (otherFills.length !== (MAX_COLORS - 1)) {
throw new Error('Invalid fills count'); throw new Error('Invalid fills count');
}
const fills = [fill, ...otherFills]; const fills = [fill, ...otherFills];
const outlines = fills.map(fillToOutline); const outlines = fills.map(fillToOutline);
@@ -147,13 +148,15 @@ export function syncLockedSpriteSet<T>(
set: SpriteSet<T> | undefined, customOutlines: boolean, fillToOutline: FillToOutline<T>, baseFill?: T, set: SpriteSet<T> | undefined, customOutlines: boolean, fillToOutline: FillToOutline<T>, baseFill?: T,
baseOutline?: T baseOutline?: T
) { ) {
if (set === undefined) if (set === undefined) {
return; return;
}
const fills = set.fills; const fills = set.fills;
if (!fills) if (!fills) {
return; return;
}
const lockFills = set.lockFills; const lockFills = set.lockFills;
@@ -177,7 +180,8 @@ export function syncLockedSpriteSet<T>(
if (lockOutlines[i]) { if (lockOutlines[i]) {
if (i === 0 && baseOutline && lockFills && lockFills[i]) { if (i === 0 && baseOutline && lockFills && lockFills[i]) {
outlines[i] = baseOutline; outlines[i] = baseOutline;
} else { }
else {
outlines[i] = fillToOutline(fills[i]); outlines[i] = fillToOutline(fills[i]);
} }
} }
@@ -202,7 +206,8 @@ function syncLockedSpritesSet2<T>(
if (locked) { if (locked) {
if (baseOutlines[i] && set.lockFills && set.lockFills[i]) { if (baseOutlines[i] && set.lockFills && set.lockFills[i]) {
set.outlines![i] = baseOutlines[i]; set.outlines![i] = baseOutlines[i];
} else { }
else {
set.outlines![i] = fillToOutline(set.fills![i]); set.outlines![i] = fillToOutline(set.fills![i]);
} }
} }
@@ -356,7 +361,8 @@ function getColorsGeneric(
if (darken) { if (darken) {
colors[i * 2 + 1] = outlines[i] ? colorToHexRGB(darkenForOutline(parseColorFast(outlines[i]!))) : defaultColor; colors[i * 2 + 1] = outlines[i] ? colorToHexRGB(darkenForOutline(parseColorFast(outlines[i]!))) : defaultColor;
} else { }
else {
colors[i * 2 + 1] = outlines[i] || defaultColor; colors[i * 2 + 1] = outlines[i] || defaultColor;
} }
} }
@@ -398,7 +404,8 @@ export const getColorsForSetNumber: GetColorsForSet<number> = (set, length, dark
if (darken) { if (darken) {
result[((i << 1) + 2) | 0] = i < outlines.length ? darkenForOutline(outlines[i] || BLACK) : BLACK; result[((i << 1) + 2) | 0] = i < outlines.length ? darkenForOutline(outlines[i] || BLACK) : BLACK;
} else { }
else {
result[((i << 1) + 2) | 0] = i < outlines.length ? (outlines[i] || BLACK) : BLACK; result[((i << 1) + 2) | 0] = i < outlines.length ? (outlines[i] || BLACK) : BLACK;
} }
} }
@@ -432,8 +439,9 @@ function createCMPalette<T>(
): Palette | undefined { ): Palette | undefined {
const size = CM_SIZE * CM_SIZE; const size = CM_SIZE * CM_SIZE;
if (cm === undefined || cm.length === 0 || cm.length > size) if (cm === undefined || cm.length === 0 || cm.length > size) {
return undefined; return undefined;
}
const result = new Uint32Array(size); const result = new Uint32Array(size);
@@ -568,7 +576,8 @@ export function releasePalettes(info: PalettePonyInfo): void {
if ('refs' in value) { if ('refs' in value) {
const palette = value as Palette; const palette = value as Palette;
releasePalette(palette); releasePalette(palette);
} else if ('palette' in value) { }
else if ('palette' in value) {
const set = value as PaletteSpriteSet; const set = value as PaletteSpriteSet;
releasePalette(set.palette); releasePalette(set.palette);
releasePalette(set.extraPalette); releasePalette(set.extraPalette);
+30 -11
View File
@@ -72,30 +72,49 @@ export function canMagic(info: PonyInfoBase<any, SpriteSetBase>) {
export function flipIris(iris: Iris): Iris { export function flipIris(iris: Iris): Iris {
if (iris === Iris.Left || iris === Iris.UpLeft) { if (iris === Iris.Left || iris === Iris.UpLeft) {
return iris + 1; return iris + 1;
} else if (iris === Iris.Right || iris === Iris.UpRight) { }
else if (iris === Iris.Right || iris === Iris.UpRight) {
return iris - 1; return iris - 1;
} else { }
else {
return iris; return iris;
} }
} }
export function flipFaceAccessoryType(type: number) { export function flipFaceAccessoryType(type: number) {
if (type === 6) return 7; if (type === 6) {
if (type === 7) return 6; return 7;
}
if (type === 7) {
return 6;
}
if (type === 9) return 10; if (type === 9) {
if (type === 10) return 9; return 10;
}
if (type === 10) {
return 9;
}
return type; return type;
} }
export function flipFaceAccessoryPattern(type: number, pattern: number) { export function flipFaceAccessoryPattern(type: number, pattern: number) {
if (type === 2) { // dark glasses if (type === 2) { // dark glasses
if (pattern === 1) return 2; if (pattern === 1) {
if (pattern === 2) return 1; return 2;
} else if (type === 11) { // large dark glasses }
if (pattern === 1) return 2; if (pattern === 2) {
if (pattern === 2) return 1; return 1;
}
}
else if (type === 11) { // large dark glasses
if (pattern === 1) {
return 2;
}
if (pattern === 2) {
return 1;
}
} }
return pattern; return pattern;
+8 -4
View File
@@ -131,8 +131,9 @@ export function generateRegionCollider<T extends Region | undefined>(region: Reg
for (let rx = minX; rx <= maxX; rx++) { for (let rx = minX; rx <= maxX; rx++) {
const r = getRegion(map, rx, ry); const r = getRegion(map, rx, ry);
if (r === undefined) if (r === undefined) {
continue; continue;
}
for (const entity of r.colliders) { for (const entity of r.colliders) {
const entityX = toScreenX(entity.x - baseX) | 0; const entityX = toScreenX(entity.x - baseX) | 0;
@@ -171,7 +172,8 @@ export function generateRegionCollider<T extends Region | undefined>(region: Reg
} }
} }
} }
} else { }
else {
for (const pc of ponyColliders) { for (const pc of ponyColliders) {
const tx0 = (baseX0 + pc.x) | 0; const tx0 = (baseX0 + pc.x) | 0;
const ty0 = (baseY0 + pc.y) | 0; const ty0 = (baseY0 + pc.y) | 0;
@@ -210,7 +212,8 @@ export function getRegionGlobal<T>(map: IMap<T>, x: number, y: number): T {
export function getRegion<T>(map: IMap<T>, x: number, y: number): T { export function getRegion<T>(map: IMap<T>, x: number, y: number): T {
if (x < 0 || y < 0 || x >= map.regionsX || y >= map.regionsY) { if (x < 0 || y < 0 || x >= map.regionsX || y >= map.regionsY) {
throw new Error(`Invalid region coords (${x}, ${y})`); throw new Error(`Invalid region coords (${x}, ${y})`);
} else { }
else {
return map.regions[((x | 0) + (y | 0) * map.regionsX) | 0]; return map.regions[((x | 0) + (y | 0) * map.regionsX) | 0];
} }
} }
@@ -218,7 +221,8 @@ export function getRegion<T>(map: IMap<T>, x: number, y: number): T {
export function getRegionUnsafe<T>(map: IMap<T>, x: number, y: number): T | undefined { export function getRegionUnsafe<T>(map: IMap<T>, x: number, y: number): T | undefined {
if (x < 0 || y < 0 || x >= map.regionsX || y >= map.regionsY) { if (x < 0 || y < 0 || x >= map.regionsX || y >= map.regionsY) {
return undefined; return undefined;
} else { }
else {
return map.regions[((x | 0) + (y | 0) * map.regionsX) | 0]; return map.regions[((x | 0) + (y | 0) * map.regionsX) | 0];
} }
} }
+4 -2
View File
@@ -80,9 +80,11 @@ export interface Person {
function getLabel(arg: LogArgument | undefined) { function getLabel(arg: LogArgument | undefined) {
if (typeof arg === 'string') { if (typeof arg === 'string') {
return arg; return arg;
} else if (arg && 'message' in arg) { }
else if (arg && 'message' in arg) {
return (arg as any).message + (arg.stack || ''); return (arg as any).message + (arg.stack || '');
} else { }
else {
return arg ? arg.toString() : ''; return arg ? arg.toString() : '';
} }
} }
+10 -5
View File
@@ -17,10 +17,12 @@ function createRegExpFromList(list: string | undefined, wholeWords = false): Reg
if (wholeWords) { if (wholeWords) {
return new RegExp(`\\b(${combined})\\b`, 'ui'); return new RegExp(`\\b(${combined})\\b`, 'ui');
} else { }
else {
return new RegExp(combined, 'ui'); return new RegExp(combined, 'ui');
} }
} else { }
else {
return undefined; return undefined;
} }
} }
@@ -47,8 +49,9 @@ export const createIsSuspiciousMessage = (general: GeneralSettings) => {
const testWholeInstant = createCachedTest(true); const testWholeInstant = createCachedTest(true);
return (text: string, { filterSwears }: GameServerSettings): Suspicious => { return (text: string, { filterSwears }: GameServerSettings): Suspicious => {
if (test(general.suspiciousMessages, text)) if (test(general.suspiciousMessages, text)) {
return Suspicious.Very; return Suspicious.Very;
}
if (filterSwears) { if (filterSwears) {
if (testSafeInstant(general.suspiciousSafeInstantMessages, text) || if (testSafeInstant(general.suspiciousSafeInstantMessages, text) ||
@@ -85,7 +88,8 @@ export const createIsSuspiciousAuth =
function tryParseJSON(value: string): any { function tryParseJSON(value: string): any {
try { try {
return JSON.parse(value); return JSON.parse(value);
} catch { }
catch {
return undefined; return undefined;
} }
} }
@@ -108,7 +112,8 @@ function matchPony(info: PonyInfoNumber, match: Partial<PonyInfo>) {
function comparePonyInfoFields(a: any, b: any): boolean { function comparePonyInfoFields(a: any, b: any): boolean {
if (typeof a === 'number' && typeof b === 'string') { if (typeof a === 'number' && typeof b === 'string') {
return a === parseColorFast(b); return a === parseColorFast(b);
} else { }
else {
return undefined as any; return undefined as any;
} }
} }
+3 -1
View File
@@ -10,7 +10,9 @@ export function addTitles(sprites: ColorExtraSets, titles: string[]): ColorExtra
} }
export function addLabels(sprites: ColorExtraSets, labels: string[]) { export function addLabels(sprites: ColorExtraSets, labels: string[]) {
sprites && sprites.forEach((s, i) => s && s[0] ? s[0]!.label = labels[i] : undefined); if (sprites) {
sprites.forEach((s, i) => s && s[0] ? s[0]!.label = labels[i] : undefined);
}
return sprites; return sprites;
} }
+2 -1
View File
@@ -213,7 +213,8 @@ export function filterString(value: string | undefined, filter: (code: number) =
code = fromSurrogate(code, extra); code = fromSurrogate(code, extra);
i++; i++;
size++; size++;
} else { }
else {
invalidSurrogate = true; invalidSurrogate = true;
} }
} }
+2 -1
View File
@@ -1478,7 +1478,8 @@ const ascii = createBadWords(true);
function tryRegex(value: string, flags: string) { function tryRegex(value: string, flags: string) {
try { try {
return new RegExp(value, flags); return new RegExp(value, flags);
} catch (e) { }
catch (e) {
console.error(e); console.error(e);
return new RegExp(/(?!.*)/); return new RegExp(/(?!.*)/);
} }
+4 -2
View File
@@ -42,9 +42,11 @@ export function getTagPalette(tag: CharacterTag, palettes: FontPalettes) {
export function canUseTag(account: AccountRoles, tag: string) { export function canUseTag(account: AccountRoles, tag: string) {
if (tag === 'mod') { if (tag === 'mod') {
return hasRole(account, 'mod'); return hasRole(account, 'mod');
} else if (tag === 'dev' || /^dev:/.test(tag)) { }
else if (tag === 'dev' || /^dev:/.test(tag)) {
return hasRole(account, 'dev'); return hasRole(account, 'dev');
} else { }
else {
return false; return false;
} }
} }
+20 -10
View File
@@ -423,7 +423,8 @@ function getTileNormal(
) { ) {
if (x >= 0 && y >= 0 && x < REGION_SIZE && y < REGION_SIZE) { if (x >= 0 && y >= 0 && x < REGION_SIZE && y < REGION_SIZE) {
return normalizeTile(tiles[x | (y << 3)], base); return normalizeTile(tiles[x | (y << 3)], base);
} else { }
else {
const mapX = clamp(x + baseX, 0, map.width - 1); const mapX = clamp(x + baseX, 0, map.width - 1);
const mapY = clamp(y + baseY, 0, map.height - 1); const mapY = clamp(y + baseY, 0, map.height - 1);
const region = getRegionGlobal(map, mapX, mapY); const region = getRegionGlobal(map, mapX, mapY);
@@ -432,7 +433,8 @@ function getTileNormal(
const regionX = mapX - region.x * REGION_SIZE; const regionX = mapX - region.x * REGION_SIZE;
const regionY = mapY - region.y * REGION_SIZE; const regionY = mapY - region.y * REGION_SIZE;
return normalizeTile(region.tiles[regionX | (regionY << 3)], base); return normalizeTile(region.tiles[regionX | (regionY << 3)], base);
} else { }
else {
return TileType.None; return TileType.None;
} }
} }
@@ -446,7 +448,8 @@ function getTileIndex(region: Region, index: number, x: number, y: number, map:
if (type === TileType.Dirt || type === TileType.ElevatedDirt) { if (type === TileType.Dirt || type === TileType.ElevatedDirt) {
baseTileIndex = 47; baseTileIndex = 47;
} else if (type !== TileType.None) { }
else if (type !== TileType.None) {
let topLeft = 0, top = 0, topRight = 0, left = 0, right = 0, bottomLeft = 0, bottom = 0, bottomRight = 0; let topLeft = 0, top = 0, topRight = 0, left = 0, right = 0, bottomLeft = 0, bottom = 0, bottomRight = 0;
if (x > 1 && y > 1 && x < (REGION_SIZE - 1) && y < (REGION_SIZE - 1)) { if (x > 1 && y > 1 && x < (REGION_SIZE - 1) && y < (REGION_SIZE - 1)) {
@@ -458,7 +461,8 @@ function getTileIndex(region: Region, index: number, x: number, y: number, map:
bottomLeft = normalizeTile(tiles[(x - 1) | (y + 1) << 3], type); bottomLeft = normalizeTile(tiles[(x - 1) | (y + 1) << 3], type);
bottom = normalizeTile(tiles[(x) | (y + 1) << 3], type); bottom = normalizeTile(tiles[(x) | (y + 1) << 3], type);
bottomRight = normalizeTile(tiles[(x + 1) | (y + 1) << 3], type); bottomRight = normalizeTile(tiles[(x + 1) | (y + 1) << 3], type);
} else { }
else {
const baseX = (region.x * REGION_SIZE) | 0; const baseX = (region.x * REGION_SIZE) | 0;
const baseY = (region.y * REGION_SIZE) | 0; const baseY = (region.y * REGION_SIZE) | 0;
topLeft = getTileNormal(tiles, baseX, baseY, x - 1, y - 1, map, type); topLeft = getTileNormal(tiles, baseX, baseY, x - 1, y - 1, map, type);
@@ -508,8 +512,9 @@ function valueToHeight(value: number, bottom: number, top: number) {
} }
export function initializeTileHeightmaps() { export function initializeTileHeightmaps() {
if (tileHeightMapsInitialized) if (tileHeightMapsInitialized) {
return; return;
}
function createTileHeightMaps(sprite: Sprite, tileType: TileTypeNumber, bottom: number, top: number) { function createTileHeightMaps(sprite: Sprite, tileType: TileTypeNumber, bottom: number, top: number) {
const sheetData = sprites.normalSpriteSheet.data!; const sheetData = sprites.normalSpriteSheet.data!;
@@ -591,11 +596,14 @@ export function getTileHeight(
return heightMaps[tx + ty * tileWidth]; return heightMaps[tx + ty * tileWidth];
} }
} }
} else if (typeNumber === TileTypeNumber.SnowOnIce) { }
else if (typeNumber === TileTypeNumber.SnowOnIce) {
return -0.2; return -0.2;
} else if (tileType === TileType.ElevatedDirt) { }
else if (tileType === TileType.ElevatedDirt) {
return 0.5; return 0.5;
} else if (typeNumber === TileTypeNumber.Boat) { }
else if (typeNumber === TileTypeNumber.Boat) {
const frame = ((gameTime / 1000) * WATER_FPS) | 0; const frame = ((gameTime / 1000) * WATER_FPS) | 0;
return waterHeight[frame % waterHeight.length]; return waterHeight[frame % waterHeight.length];
} }
@@ -610,7 +618,8 @@ export function getTile<T>(map: IMap<T>, x: number, y: number): TileType {
const regionX = Math.floor(x - region.x * REGION_SIZE); const regionX = Math.floor(x - region.x * REGION_SIZE);
const regionY = Math.floor(y - region.y * REGION_SIZE); const regionY = Math.floor(y - region.y * REGION_SIZE);
return getRegionTile(region, regionX, regionY); return getRegionTile(region, regionX, regionY);
} else { }
else {
return TileType.None; return TileType.None;
} }
} }
@@ -618,8 +627,9 @@ export function getTile<T>(map: IMap<T>, x: number, y: number): TileType {
export function setTile(map: WorldMap, worldX: number, worldY: number, type: TileType) { export function setTile(map: WorldMap, worldX: number, worldY: number, type: TileType) {
const region = getRegionGlobal(map, worldX, worldY); const region = getRegionGlobal(map, worldX, worldY);
if (!region) if (!region) {
return; return;
}
const x = Math.floor(worldX - region.x * REGION_SIZE); const x = Math.floor(worldX - region.x * REGION_SIZE);
const y = Math.floor(worldY - region.y * REGION_SIZE); const y = Math.floor(worldY - region.y * REGION_SIZE);
+6 -3
View File
@@ -31,7 +31,8 @@ export function timeStart(name: string) {
entry.time = performance.now(); entry.time = performance.now();
entry.name = name; entry.name = name;
entriesCount++; entriesCount++;
} else { }
else {
console.warn(`exceeded timing entry limit`); console.warn(`exceeded timing entry limit`);
} }
} }
@@ -44,7 +45,8 @@ export function timeEnd() {
entry.time = performance.now(); entry.time = performance.now();
entry.name = undefined; entry.name = undefined;
entriesCount++; entriesCount++;
} else { }
else {
console.warn(`exceeded timing entry limit`); console.warn(`exceeded timing entry limit`);
} }
} }
@@ -70,7 +72,8 @@ export function timingCollate(): TimingResult[] {
if (entry.name !== undefined) { if (entry.name !== undefined) {
startStack.push({ ...entry, excludedTime: 0 }); startStack.push({ ...entry, excludedTime: 0 });
} else { }
else {
const start = startStack.pop()!; const start = startStack.pop()!;
const name = start.name!; const name = start.name!;
const time = entry.time - start.time; const time = entry.time - start.time;
+35 -16
View File
@@ -52,11 +52,14 @@ export function formatDuration(duration: number) {
if (d > 0) { if (d > 0) {
return h ? `${d}d ${h}h` : `${d}d`; return h ? `${d}d ${h}h` : `${d}d`;
} else if (h > 0) { }
else if (h > 0) {
return m ? `${h}h ${m}m` : `${h}h`; return m ? `${h}h ${m}m` : `${h}h`;
} else if (m > 0) { }
else if (m > 0) {
return s ? `${m}m ${s}s` : `${m}m`; return s ? `${m}m ${s}s` : `${m}m`;
} else { }
else {
return `${s}s`; return `${s}s`;
} }
} }
@@ -93,7 +96,8 @@ export function createValidBirthDate(day: number, month: number, year: number) {
year >= (currentYear - 120) && year < currentYear year >= (currentYear - 120) && year < currentYear
) { ) {
return date; return date;
} else { }
else {
return undefined; return undefined;
} }
} }
@@ -165,7 +169,9 @@ export function toInt(value: any): number {
} }
export function dispose<T extends { dispose(): void; }>(obj: T | undefined): undefined { export function dispose<T extends { dispose(): void; }>(obj: T | undefined): undefined {
obj && obj.dispose(); if (obj) {
obj.dispose();
}
return undefined; return undefined;
} }
@@ -267,7 +273,8 @@ export function removeItem<T>(items: T[], item: T): boolean {
if (index !== -1) { if (index !== -1) {
items.splice(index, 1); items.splice(index, 1);
return true; return true;
} else { }
else {
return false; return false;
} }
} }
@@ -279,7 +286,8 @@ export function removeItemFast<T>(items: T[], item: T): boolean {
items[index] = items[items.length - 1]; items[index] = items[items.length - 1];
items.pop(); items.pop();
return true; return true;
} else { }
else {
return false; return false;
} }
} }
@@ -291,7 +299,8 @@ export function removeById<U, T extends { id: U }>(items: T[], id: U): T | undef
const item = items[index]; const item = items[index];
items.splice(index, 1); items.splice(index, 1);
return item; return item;
} else { }
else {
return undefined; return undefined;
} }
} }
@@ -316,7 +325,8 @@ export function pushUniq<T>(array: T[], item: T) {
if (index === -1) { if (index === -1) {
array.push(item); array.push(item);
return array.length; return array.length;
} else { }
else {
return index + 1; return index + 1;
} }
} }
@@ -433,13 +443,17 @@ export function createError(status: number, data: string | { error: string; }):
return new Error(PROTECTION_ERROR); return new Error(PROTECTION_ERROR);
// } else if (status === 400) { // } else if (status === 400) {
// return new Error('Bad Request'); // return new Error('Bad Request');
} else if (status === 403) { }
else if (status === 403) {
return new Error(ACCESS_ERROR); return new Error(ACCESS_ERROR);
} else if (status === 404) { }
else if (status === 404) {
return new Error(NOT_FOUND_ERROR); return new Error(NOT_FOUND_ERROR);
} else if (typeof data === 'string') { }
else if (typeof data === 'string') {
return new Error(data || OFFLINE_ERROR); return new Error(data || OFFLINE_ERROR);
} else { }
else {
return new Error((data && data.error) || OFFLINE_ERROR); return new Error((data && data.error) || OFFLINE_ERROR);
} }
} }
@@ -455,7 +469,8 @@ export function observableToPromise<T>(observable: Observable<T>) {
try { try {
error = JSON.parse(error); error = JSON.parse(error);
} catch { } }
catch { }
const e: RequestError = createError(status || 0, error); const e: RequestError = createError(status || 0, error);
e.status = status; e.status = status;
@@ -518,7 +533,9 @@ export function processCommand(text: string) {
} }
export function parseSeason(value?: string): Season | undefined { export function parseSeason(value?: string): Season | undefined {
if (!value) return undefined; if (!value) {
return undefined;
}
switch (value.toLowerCase()) { switch (value.toLowerCase()) {
case 'spring': return Season.Spring; case 'spring': return Season.Spring;
case 'summer': return Season.Summer; case 'summer': return Season.Summer;
@@ -529,7 +546,9 @@ export function parseSeason(value?: string): Season | undefined {
} }
export function parseHoliday(value?: string): Holiday | undefined { export function parseHoliday(value?: string): Holiday | undefined {
if (!value) return undefined; if (!value) {
return undefined;
}
switch (value.toLowerCase()) { switch (value.toLowerCase()) {
case 'none': return Holiday.None; case 'none': return Holiday.None;
case 'halloween': return Holiday.Halloween; case 'halloween': return Holiday.Halloween;
@@ -145,9 +145,15 @@ export class AdminAccountDetails implements OnInit, OnDestroy {
} }
ngOnDestroy() { ngOnDestroy() {
this.model.updated = () => { }; this.model.updated = () => { };
this.authsSubscription && this.authsSubscription.unsubscribe(); if (this.authsSubscription) {
this.accountSubscription && this.accountSubscription.unsubscribe(); this.authsSubscription.unsubscribe();
this.originsSubscription && this.originsSubscription.unsubscribe(); }
if (this.accountSubscription) {
this.accountSubscription.unsubscribe();
}
if (this.originsSubscription) {
this.originsSubscription.unsubscribe();
}
} }
refresh() { refresh() {
const account = this.account; const account = this.account;
@@ -160,10 +166,14 @@ export class AdminAccountDetails implements OnInit, OnDestroy {
this.accountObject = undefined; this.accountObject = undefined;
this.loadingDuplicates = false; this.loadingDuplicates = false;
this.authsSubscription && this.authsSubscription.unsubscribe(); if (this.authsSubscription) {
this.authsSubscription.unsubscribe();
}
this.authsSubscription = undefined; this.authsSubscription = undefined;
this.originsSubscription && this.originsSubscription.unsubscribe(); if (this.originsSubscription) {
this.originsSubscription.unsubscribe();
}
this.originsSubscription = undefined; this.originsSubscription = undefined;
this.auths = []; this.auths = [];
@@ -201,7 +211,8 @@ export class AdminAccountDetails implements OnInit, OnDestroy {
this.originsSubscription = this.model.accountOrigins this.originsSubscription = this.model.accountOrigins
.subscribe(account._id, origins => this.origins = origins || []); .subscribe(account._id, origins => this.origins = origins || []);
} else { }
else {
this.duplicates = []; this.duplicates = [];
this.ignores = []; this.ignores = [];
this.ignoredBy = []; this.ignoredBy = [];
@@ -468,7 +479,8 @@ export class AdminAccountDetails implements OnInit, OnDestroy {
if (merge.data) { if (merge.data) {
return `${mergeInfo('ACCOUNT', merge.data.account)}\n\n${mergeInfo('MERGED', merge.data.merge)}`; return `${mergeInfo('ACCOUNT', merge.data.account)}\n\n${mergeInfo('MERGED', merge.data.merge)}`;
} else { }
else {
return '<empty>'; return '<empty>';
} }
} }
@@ -552,7 +564,9 @@ export class AdminAccountDetails implements OnInit, OnDestroy {
} }
private update() { private update() {
if (this.id) { if (this.id) {
this.accountSubscription && this.accountSubscription.unsubscribe(); if (this.accountSubscription) {
this.accountSubscription.unsubscribe();
}
this.accountSubscription = this.id ? this.model.accounts.subscribe(this.id, a => this.setAccount(a)) : undefined; this.accountSubscription = this.id ? this.model.accounts.subscribe(this.id, a => this.setAccount(a)) : undefined;
this.events = this.model.events this.events = this.model.events
@@ -49,7 +49,9 @@ export class AdminOther implements OnInit, OnDestroy {
}); });
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
saveFields() { saveFields() {
let settings: any = {}; let settings: any = {};
@@ -67,7 +69,8 @@ export class AdminOther implements OnInit, OnDestroy {
try { try {
compact(this.suspiciousPonies!.split(/\n/g).map(x => x.trim())).map(x => JSON.parse(x)); compact(this.suspiciousPonies!.split(/\n/g).map(x => x.trim())).map(x => JSON.parse(x));
this.model.updateSettings({ suspiciousPonies: this.suspiciousPonies }); this.model.updateSettings({ suspiciousPonies: this.suspiciousPonies });
} catch (e) { }
catch (e) {
this.suspiciousPoniesError = isErrorAlike(e) ? e.message : 'Unknown error'; this.suspiciousPoniesError = isErrorAlike(e) ? e.message : 'Unknown error';
} }
} }
@@ -90,7 +90,8 @@ export class AdminPonies implements OnInit {
} }
this.items = result.items; this.items = result.items;
} else { }
else {
this.items = []; this.items = [];
} }
}) })
@@ -112,7 +112,8 @@ export class AdminReportsPerf {
element.style.left = `${x + 10}px`; element.style.left = `${x + 10}px`;
element.style.top = `${y + 10}px`; element.style.top = `${y + 10}px`;
element.innerText = tooltip.text; element.innerText = tooltip.text;
} else { }
else {
element.style.display = 'none'; element.style.display = 'none';
} }
} }
@@ -208,8 +209,9 @@ export class AdminReportsPerf {
this.tooltips.length = 0; this.tooltips.length = 0;
if (!this.timings.length) if (!this.timings.length) {
return; return;
}
const firstTime = this.timings[0].time; const firstTime = this.timings[0].time;
const startTime = this.startTime; const startTime = this.startTime;
@@ -254,7 +256,8 @@ export class AdminReportsPerf {
for (const entry of this.timings) { for (const entry of this.timings) {
if (entry.type === TimingEntryType.Start) { if (entry.type === TimingEntryType.Start) {
startStack.push(entry); startStack.push(entry);
} else { }
else {
const start = startStack.pop()!; const start = startStack.pop()!;
const name = start.name!; const name = start.name!;
const startX = timeToX(start.time); const startX = timeToX(start.time);
@@ -267,9 +270,11 @@ export class AdminReportsPerf {
if (startStack.length === 0) { if (startStack.length === 0) {
context.fillStyle = '#efc457'; context.fillStyle = '#efc457';
text = `${text} (${time.toFixed(2)} ms) ${(100 * time / frameTime).toFixed(0)}%`; text = `${text} (${time.toFixed(2)} ms) ${(100 * time / frameTime).toFixed(0)}%`;
} else if (/\(\)$/.test(name)) { }
else if (/\(\)$/.test(name)) {
context.fillStyle = '#d4ecc6'; context.fillStyle = '#d4ecc6';
} else { }
else {
context.fillStyle = '#c6dcec'; context.fillStyle = '#c6dcec';
} }
@@ -298,7 +303,8 @@ export class AdminReportsPerf {
for (const entry of this.timings) { for (const entry of this.timings) {
if (entry.type === TimingEntryType.Start) { if (entry.type === TimingEntryType.Start) {
startStack.push({ ...entry, excludedTime: 0 }); startStack.push({ ...entry, excludedTime: 0 });
} else { }
else {
const start = startStack.pop()!; const start = startStack.pop()!;
const name = start.name!; const name = start.name!;
const time = entry.time - start.time; const time = entry.time - start.time;
+6 -3
View File
@@ -41,11 +41,14 @@ export class AdminApp {
get loading() { get loading() {
if (!this.model.initialized) { if (!this.model.initialized) {
return 'Initializing'; return 'Initializing';
} else if (!this.model.connected) { }
else if (!this.model.connected) {
return 'Connecting'; return 'Connecting';
} else if (!this.model.loaded) { }
else if (!this.model.loaded) {
return 'Loading'; return 'Loading';
} else { }
else {
return ''; return '';
} }
} }
+2 -1
View File
@@ -48,7 +48,8 @@ export abstract class BaseTable<T> {
sortBy(field: string) { sortBy(field: string) {
if (this.sortedBy === field) { if (this.sortedBy === field) {
this.sortedAsc = !this.sortedAsc; this.sortedAsc = !this.sortedAsc;
} else { }
else {
this.sortedBy = field; this.sortedBy = field;
this.sortedAsc = true; this.sortedAsc = true;
} }
@@ -7,8 +7,9 @@ import { transliterate } from 'transliteration';
}) })
export class TranslitPipe implements PipeTransform { export class TranslitPipe implements PipeTransform {
transform(value: string) { transform(value: string) {
if (!value || /^[a-z0-9-_.,[]!@#$%^&*{}|\/\\ ]+$/i.test(value)) if (!value || /^[a-z0-9-_.,[]!@#$%^&*{}|\/\\ ]+$/i.test(value)) {
return undefined; return undefined;
}
const translit = transliterate(value); const translit = transliterate(value);
return translit !== value ? translit : undefined; return translit !== value ? translit : undefined;
@@ -20,7 +20,9 @@ export class AccountInfoRemote implements OnDestroy {
constructor(private model: AdminModel) { constructor(private model: AdminModel) {
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
get accountId() { get accountId() {
return this._accountId; return this._accountId;
@@ -134,11 +134,14 @@ export class AccountInfo implements OnInit, OnChanges {
if (this.account.flags) { if (this.account.flags) {
return 'text-banned'; return 'text-banned';
} else if (!counters && !this.account.supporter) { }
else if (!counters && !this.account.supporter) {
return 'text-muted'; return 'text-muted';
} else if (counters && ((counters.spam || 0) > 100 || (counters.swears || 0) > 10)) { }
else if (counters && ((counters.spam || 0) > 100 || (counters.swears || 0) > 10)) {
return 'text-alert'; return 'text-alert';
} else { }
else {
return 'text-present'; return 'text-present';
} }
} }
@@ -190,7 +193,9 @@ export class AccountInfo implements OnInit, OnChanges {
this.alertModalRef = this.modalService.show(this.alertModal, { ignoreBackdropClick: true }); this.alertModalRef = this.modalService.show(this.alertModal, { ignoreBackdropClick: true });
} }
cancelAlert() { cancelAlert() {
this.alertModalRef && this.alertModalRef.hide(); if (this.alertModalRef) {
this.alertModalRef.hide();
}
this.alertModalRef = undefined; this.alertModalRef = undefined;
} }
confirmAlert() { confirmAlert() {
@@ -206,7 +211,8 @@ export class AccountInfo implements OnInit, OnChanges {
if (cached && cached.generatedAt > threshold.getTime()) { if (cached && cached.generatedAt > threshold.getTime()) {
this.duplicates = cached; this.duplicates = cached;
} else { }
else {
this.model.getAllDuplicatesQuickInfo(account._id) this.model.getAllDuplicatesQuickInfo(account._id)
.then(duplicates => { .then(duplicates => {
if (duplicates) { if (duplicates) {
@@ -42,7 +42,8 @@ export class AdminChatLog implements OnDestroy {
set autoRefresh(value: boolean) { set autoRefresh(value: boolean) {
if (value) { if (value) {
this.refreshInterval = this.refreshInterval || setInterval(() => this.refresh(), 10 * 1000); this.refreshInterval = this.refreshInterval || setInterval(() => this.refresh(), 10 * 1000);
} else { }
else {
this.stopInterval(); this.stopInterval();
} }
} }
@@ -75,7 +76,8 @@ export class AdminChatLog implements OnDestroy {
add(account: Account) { add(account: Account) {
if (!this.account) { if (!this.account) {
this.show(account); this.show(account);
} else if (account !== this.account && !includes(this.accounts, account)) { }
else if (account !== this.account && !includes(this.accounts, account)) {
this.date = this.date || this.today; this.date = this.date || this.today;
this.accounts.push(account); this.accounts.push(account);
this.refresh(); this.refresh();
@@ -116,7 +118,8 @@ export class AdminChatLog implements OnDestroy {
if (this.account) { if (this.account) {
const accounts = [this.account._id, ...this.accounts.map(a => a._id)]; const accounts = [this.account._id, ...this.accounts.map(a => a._id)];
this.handleChat(this.model.accountsFormattedChat(accounts, date)); this.handleChat(this.model.accountsFormattedChat(accounts, date));
} else if (this.search) { }
else if (this.search) {
this.handleChat(this.model.searchFormattedChat(this.search, date)); this.handleChat(this.model.searchFormattedChat(this.search, date));
} }
} }
@@ -177,7 +180,8 @@ export class AdminChatLog implements OnDestroy {
this.atNode += i; this.atNode += i;
this.processIdle = requestIdleCallback(() => this.processNodes()); this.processIdle = requestIdleCallback(() => this.processNodes());
} else { }
else {
this.nodesToProcess = undefined; this.nodesToProcess = undefined;
} }
} }
@@ -30,12 +30,16 @@ export class AuthInfoEdit implements OnDestroy {
if (this.authId !== value) { if (this.authId !== value) {
this._authId = value; this._authId = value;
this.auth = undefined; this.auth = undefined;
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
this.subscription = value ? this.model.auths.subscribe(value, auth => this.auth = auth) : undefined; this.subscription = value ? this.model.auths.subscribe(value, auth => this.auth = auth) : undefined;
} }
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
removeAuth(auth: Auth | undefined) { removeAuth(auth: Auth | undefined) {
if (auth && confirm('Are you sure?')) { if (auth && confirm('Are you sure?')) {
@@ -23,11 +23,15 @@ export class AuthInfoRemote implements OnDestroy {
if (this.authId !== value) { if (this.authId !== value) {
this._authId = value; this._authId = value;
this.auth = undefined; this.auth = undefined;
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
this.subscription = value ? this.model.auths.subscribe(value, auth => this.auth = auth) : undefined; this.subscription = value ? this.model.auths.subscribe(value, auth => this.auth = auth) : undefined;
} }
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
} }
@@ -26,7 +26,9 @@ export class AuthListRemote implements OnDestroy {
this._accountId = value; this._accountId = value;
this.auths = []; this.auths = [];
this.loading = true; this.loading = true;
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
this.subscription = value ? this.model.accountAuths.subscribe(value, auths => { this.subscription = value ? this.model.accountAuths.subscribe(value, auths => {
this.auths = auths || []; this.auths = auths || [];
this.loading = false; this.loading = false;
@@ -34,6 +36,8 @@ export class AuthListRemote implements OnDestroy {
} }
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
} }
@@ -37,9 +37,11 @@ export class BanIcon implements OnInit, OnDestroy, OnChanges {
get className() { get className() {
if (this.isPerma) { if (this.isPerma) {
return 'text-banned'; return 'text-banned';
} else if (this.isTimedOut) { }
else if (this.isTimedOut) {
return 'text-alert'; return 'text-alert';
} else { }
else {
return 'text-muted'; return 'text-muted';
} }
} }
@@ -48,7 +48,8 @@ export class EventsTable {
onShowChat(e: MouseEvent, event: Event, account: Account | undefined) { onShowChat(e: MouseEvent, event: Event, account: Account | undefined) {
if (e.shiftKey) { if (e.shiftKey) {
this.addChat.emit({ event, account }); this.addChat.emit({ event, account });
} else { }
else {
this.showChat.emit({ event, account }); this.showChat.emit({ event, account });
} }
} }
+3 -1
View File
@@ -24,7 +24,9 @@ export class FromNow implements OnInit, OnDestroy, OnChanges {
this.update(); this.update();
} }
ngOnDestroy() { ngOnDestroy() {
this.unsubscribe && this.unsubscribe(); if (this.unsubscribe) {
this.unsubscribe();
}
} }
private update() { private update() {
const text = this.date const text = this.date
@@ -23,11 +23,15 @@ export class OriginInfoRemote implements OnDestroy {
if (this.originIP !== value) { if (this.originIP !== value) {
this._originIP = value; this._originIP = value;
this.origin = undefined; this.origin = undefined;
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
this.subscription = value ? this.model.origins.subscribe(value, origin => this.origin = origin) : undefined; this.subscription = value ? this.model.origins.subscribe(value, origin => this.origin = origin) : undefined;
} }
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
} }
@@ -24,11 +24,15 @@ export class OriginListRemote implements OnDestroy {
if (this.accountId !== value) { if (this.accountId !== value) {
this._accountId = value; this._accountId = value;
this.origins = []; this.origins = [];
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
this.subscription = value ? this.model.accountOrigins.subscribe(value, x => this.origins = x || []) : undefined; this.subscription = value ? this.model.accountOrigins.subscribe(value, x => this.origins = x || []) : undefined;
} }
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
} }
@@ -24,11 +24,15 @@ export class PonyInfoRemote implements OnDestroy {
if (this.ponyId !== value) { if (this.ponyId !== value) {
this._ponyId = value; this._ponyId = value;
this.pony = undefined; this.pony = undefined;
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
this.subscription = value ? this.model.ponies.subscribe(value, pony => this.pony = pony) : undefined; this.subscription = value ? this.model.ponies.subscribe(value, pony => this.pony = pony) : undefined;
} }
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
} }
@@ -25,9 +25,11 @@ export class PonyInfo implements OnChanges {
if (this.pony) { if (this.pony) {
if (isForbiddenName(this.pony.name)) { if (isForbiddenName(this.pony.name)) {
this.labelClass = 'badge-forbidden'; this.labelClass = 'badge-forbidden';
} else if (hasFlag(this.pony.flags, CharacterFlags.BadCM)) { }
else if (hasFlag(this.pony.flags, CharacterFlags.BadCM)) {
this.labelClass = 'badge-danger'; this.labelClass = 'badge-danger';
} else { }
else {
this.labelClass = 'badge-none'; this.labelClass = 'badge-none';
} }
} }
@@ -39,7 +39,9 @@ export class PonyListRemote implements OnDestroy {
this.ponies = []; this.ponies = [];
this.ponyInfos = []; this.ponyInfos = [];
this.loading = true; this.loading = true;
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
this.subscription = value ? this.model.accountPonies.subscribe(value, (x = []) => { this.subscription = value ? this.model.accountPonies.subscribe(value, (x = []) => {
this.ponyInfos = x; this.ponyInfos = x;
this.updatePonies(); this.updatePonies();
@@ -48,7 +50,9 @@ export class PonyListRemote implements OnDestroy {
} }
} }
ngOnDestroy() { ngOnDestroy() {
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
} }
remove(characterId: string) { remove(characterId: string) {
if (confirm('Are you sure?')) { if (confirm('Are you sure?')) {
+2 -1
View File
@@ -193,7 +193,8 @@ export class App implements OnInit, OnDestroy {
if (isSelected(this.game, message.entityId)) { if (isSelected(this.game, message.entityId)) {
this.game.whisperTo = entity; this.game.whisperTo = entity;
chatBox.setChatType('whisper'); chatBox.setChatType('whisper');
} else { }
else {
this.game.select(entity as Pony); this.game.select(entity as Pony);
} }
} }
+5 -2
View File
@@ -490,8 +490,11 @@ export class Character implements OnInit, OnDestroy {
await this.model.savePony(pony, true); await this.model.savePony(pony, true);
imported++; imported++;
} }
} catch (e) { }
DEVELOPMENT && console.error(e); catch (e) {
if (DEVELOPMENT) {
console.error(e);
}
} }
} }
+3 -1
View File
@@ -28,7 +28,9 @@ export class Help {
ngAfterViewInit() { ngAfterViewInit() {
this.route.fragment.subscribe(f => { this.route.fragment.subscribe(f => {
const element = document.querySelector('#' + f); const element = document.querySelector('#' + f);
if (element) setTimeout(() => element.scrollIntoView(), 10); if (element) {
setTimeout(() => element.scrollIntoView(), 10);
}
}); });
} }
} }
+6 -3
View File
@@ -177,8 +177,9 @@ export class AdminModel {
return this.liveEvents.finished; return this.liveEvents.finished;
} }
initialize(live: boolean) { initialize(live: boolean) {
if (this.initializedLive) if (this.initializedLive) {
return; return;
}
notification.requestPermission(); notification.requestPermission();
@@ -545,8 +546,9 @@ export class AdminModel {
} }
private updateStateTimeout: any; private updateStateTimeout: any;
private updateState(): void { private updateState(): void {
if (!this.running) if (!this.running) {
return; return;
}
clearTimeout(this.updateStateTimeout); clearTimeout(this.updateStateTimeout);
@@ -590,7 +592,8 @@ export class AdminModel {
function decodeDate(value: number | undefined, base: string | undefined): Date { function decodeDate(value: number | undefined, base: string | undefined): Date {
if (value == null || base == null) { if (value == null || base == null) {
return new Date(0); return new Date(0);
} else { }
else {
const d = new Date(base); const d = new Date(base);
d.setTime(d.getTime() + value); d.setTime(d.getTime() + value);
return d; return d;
+19 -11
View File
@@ -76,7 +76,8 @@ function fadeOut(track: Track, id: number, volume: number) {
howl howl
.fade(volume, 0, 1000, id) .fade(volume, 0, 1000, id)
.once('fade', () => howl.pause(id).stop(id), id); .once('fade', () => howl.pause(id).stop(id), id);
} else { }
else {
howl howl
.volume(0, id) .volume(0, id)
.pause(id) .pause(id)
@@ -124,7 +125,8 @@ export class Audio {
if (this.playing) { if (this.playing) {
if (this.instance) { if (this.instance) {
this.setInstanceVolume(this.instance, this.volume); this.setInstanceVolume(this.instance, this.volume);
} else if (this.volume) { }
else if (this.volume) {
this.playRandomTrack(); this.playRandomTrack();
} }
} }
@@ -137,12 +139,14 @@ export class Audio {
if (this.volume) { if (this.volume) {
if (this.instance) { if (this.instance) {
this.resumeInstance(this.instance); this.resumeInstance(this.instance);
} else { }
else {
this.playRandomTrack(); this.playRandomTrack();
} }
} }
} }
} catch (e) { }
catch (e) {
console.error(e); console.error(e);
} }
} }
@@ -150,10 +154,12 @@ export class Audio {
if (FADE_TRACKS) { if (FADE_TRACKS) {
if (this.playing && this.volume) { if (this.playing && this.volume) {
this.playRandomTrack(); this.playRandomTrack();
} else { }
else {
this.play(); this.play();
} }
} else { }
else {
this.play(); this.play();
} }
} }
@@ -175,15 +181,15 @@ export class Audio {
private switchToTrack(track: Track) { private switchToTrack(track: Track) {
if (this.instance && this.instance.track === track) { if (this.instance && this.instance.track === track) {
return false; return false;
} else { }
else {
this.stopInstance(this.instance); this.stopInstance(this.instance);
this.instance = this.playTrack(track); this.instance = this.playTrack(track);
return true; return true;
} }
} }
playRandomTrack() { playRandomTrack() {
while (!this.switchToTrack(sample(this.tracks)!)) while (!this.switchToTrack(sample(this.tracks)!)) {}
;
this.loops = random(4, 7); this.loops = random(4, 7);
} }
@@ -215,7 +221,8 @@ export class Audio {
if (volume && !howl.playing(instance.id)) { if (volume && !howl.playing(instance.id)) {
howl.play(instance.id); howl.play(instance.id);
} else if (!volume && howl.playing(instance.id)) { }
else if (!volume && howl.playing(instance.id)) {
howl.pause(instance.id); howl.pause(instance.id);
} }
} }
@@ -243,7 +250,8 @@ export class Audio {
if (this.volume && this.playing) { if (this.volume && this.playing) {
this.playRandomTrack(); this.playRandomTrack();
} else { }
else {
this.stopInstance(this.instance); this.stopInstance(this.instance);
} }
} }
+2 -1
View File
@@ -13,7 +13,8 @@ export class AuthGuard implements CanActivate {
.then(account => { .then(account => {
if (account) { if (account) {
return true; return true;
} else { }
else {
this.router.navigate(['/']); this.router.navigate(['/']);
return false; return false;
} }
+14 -7
View File
@@ -14,7 +14,7 @@ import { meetsRequirement } from '../../common/accountUtils';
import { isLanguage, isFocused, sortServersForRussian } from '../../client/clientUtils'; import { isLanguage, isFocused, sortServersForRussian } from '../../client/clientUtils';
import { StorageService } from './storageService'; import { StorageService } from './storageService';
export interface ClientSocketService extends SocketService<ClientActions, IServerActions> { } export type ClientSocketService = SocketService<ClientActions, IServerActions>;
function createSocket( function createSocket(
gameService: GameService, game: PonyTownGame, model: Model, zone: NgZone, options: ClientOptions, gameService: GameService, game: PonyTownGame, model: Model, zone: NgZone, options: ClientOptions,
@@ -183,7 +183,8 @@ export class GameService {
if (reason === LeaveReason.Swearing) { if (reason === LeaveReason.Swearing) {
this.leftMessage = 'Kicked for swearing or inappropriate language'; this.leftMessage = 'Kicked for swearing or inappropriate language';
this.locked = true; this.locked = true;
} else { }
else {
this.leftMessage = undefined; this.leftMessage = undefined;
} }
@@ -233,11 +234,14 @@ export class GameService {
private getAndUpdateStatus(account: AccountData | undefined) { private getAndUpdateStatus(account: AccountData | undefined) {
if (this.joining || this.playing || !account || !isFocused()) { if (this.joining || this.playing || !account || !isFocused()) {
return Promise.resolve(); return Promise.resolve();
} else { }
else {
return this.model.status(this.initialized) return this.model.status(this.initialized)
.then(status => this.updateStatus(account, status)) .then(status => this.updateStatus(account, status))
.catch((e: RequestError) => { .catch((e: RequestError) => {
DEVELOPMENT && console.error(e); if (DEVELOPMENT) {
console.error(e);
}
this.offline = e.message === OFFLINE_ERROR; this.offline = e.message === OFFLINE_ERROR;
this.versionError = e.message === VERSION_ERROR; this.versionError = e.message === VERSION_ERROR;
this.protectionError = e.message === PROTECTION_ERROR; this.protectionError = e.message === PROTECTION_ERROR;
@@ -255,14 +259,16 @@ export class GameService {
if (existing) { if (existing) {
merge(existing, server); merge(existing, server);
} else if ('name' in server) { }
else if ('name' in server) {
const info = server as ServerInfo; const info = server as ServerInfo;
info.countryFlags = info.flag && /^[a-z]{2}( [a-z]{2})*$/.test(info.flag) ? info.flag.split(/ /g) : []; info.countryFlags = info.flag && /^[a-z]{2}( [a-z]{2})*$/.test(info.flag) ? info.flag.split(/ /g) : [];
if (info.name && account && meetsRequirement(account, info.require)) { if (info.name && account && meetsRequirement(account, info.require)) {
this.servers.push(info); this.servers.push(info);
} }
} else { }
else {
// got new server on the list // got new server on the list
this.initialized = false; this.initialized = false;
} }
@@ -302,7 +308,8 @@ export class GameService {
if (socket.isConnected) { if (socket.isConnected) {
clearInterval(interval); clearInterval(interval);
this.zone.run(resolve); this.zone.run(resolve);
} else if (!this.joining) { }
else if (!this.joining) {
clearInterval(interval); clearInterval(interval);
this.zone.run(() => reject(new Error('Cancelled (poll)'))); this.zone.run(() => reject(new Error('Cancelled (poll)')));
} }
@@ -35,7 +35,8 @@ export class IntervalUpdateService {
return (on: boolean) => { return (on: boolean) => {
if (on && !unsubscribe) { if (on && !unsubscribe) {
unsubscribe = this.subscribe(action); unsubscribe = this.subscribe(action);
} else if (!on && unsubscribe) { }
else if (!on && unsubscribe) {
unsubscribe(); unsubscribe();
unsubscribe = undefined; unsubscribe = undefined;
} }
+8 -4
View File
@@ -51,7 +51,8 @@ export class LiveCollection<T extends Document> {
if (removeFromList || this.options.deleteItems) { if (removeFromList || this.options.deleteItems) {
removeItem(this.items, item); removeItem(this.items, item);
this.itemsMap.delete(key); this.itemsMap.delete(key);
} else if (deleted) { }
else if (deleted) {
item.deleted = true; item.deleted = true;
} }
@@ -64,8 +65,9 @@ export class LiveCollection<T extends Document> {
return this.server.assignAccount(this.name, id, account); return this.server.assignAccount(this.name, id, account);
} }
live(): Promise<void> { live(): Promise<void> {
if (!this.running) if (!this.running) {
return Promise.resolve(); return Promise.resolve();
}
clearTimeout(this.liveTimeout); clearTimeout(this.liveTimeout);
@@ -129,11 +131,13 @@ export class LiveCollection<T extends Document> {
if (doc) { if (doc) {
if (this.options.onUpdate) { if (this.options.onUpdate) {
this.options.onUpdate(doc, update); this.options.onUpdate(doc, update);
} else { }
else {
Object.assign(doc, update); Object.assign(doc, update);
} }
all.push(doc); all.push(doc);
} else if (!liveFetch || !this.options.ignore || !this.options.ignore(update)) { }
else if (!liveFetch || !this.options.ignore || !this.options.ignore(update)) {
this.push(update); this.push(update);
added.push(update); added.push(update);
all.push(update); all.push(update);
+32 -15
View File
@@ -78,7 +78,8 @@ export function getPonyTag(pony: PonyObject, account: AccountData | undefined) {
if (account) { if (account) {
const tag = canUseTag(account, pony.tag || '') ? pony.tag : undefined; const tag = canUseTag(account, pony.tag || '') ? pony.tag : undefined;
return (!tag && account.supporter && !pony.hideSupport) ? `sup${account.supporter}` : tag; return (!tag && account.supporter && !pony.hideSupport) ? `sup${account.supporter}` : tag;
} else { }
else {
return undefined; return undefined;
} }
} }
@@ -179,7 +180,8 @@ export class Model {
modStatus.mod = isMod(account); modStatus.mod = isMod(account);
modStatus.check = account.check; modStatus.check = account.check;
modStatus.editor = account.editor || modStatus.editor; modStatus.editor = account.editor || modStatus.editor;
} catch { } }
catch { }
if (modStatus.editor) { if (modStatus.editor) {
modStatus.editor.typeToName.forEach(({ type, name }) => entityTypeToName.set(type, name)); modStatus.editor.typeToName.forEach(({ type, name }) => entityTypeToName.set(type, name));
@@ -208,18 +210,22 @@ export class Model {
if (e.message === ACCESS_ERROR) { if (e.message === ACCESS_ERROR) {
this.loading = false; this.loading = false;
this.storage.setItem('vid', '---'); this.storage.setItem('vid', '---');
} else if (e.message === LIMIT_ERROR) { }
else if (e.message === LIMIT_ERROR) {
this.loadingError = 'request-limit'; this.loadingError = 'request-limit';
return delay(5000).then(() => this.initializeAccount()); return delay(5000).then(() => this.initializeAccount());
} else if (e.message === OFFLINE_ERROR) { }
else if (e.message === OFFLINE_ERROR) {
this.loadingError = 'cannot-connect'; this.loadingError = 'cannot-connect';
return delay(5000).then(() => this.initializeAccount()); return delay(5000).then(() => this.initializeAccount());
} else if (e.message === PROTECTION_ERROR) { }
else if (e.message === PROTECTION_ERROR) {
this.loadingError = 'cloudflare-error'; this.loadingError = 'cloudflare-error';
this.protectionErrors.next(); this.protectionErrors.next();
// } else if (e.message === VERSION_ERROR) { // } else if (e.message === VERSION_ERROR) {
// this.updating = true; // this.updating = true;
} else { }
else {
setTimeout(() => this.loadingError = 'unexpected-error', 5 * SECOND); setTimeout(() => this.loadingError = 'unexpected-error', 5 * SECOND);
console.error(e); console.error(e);
} }
@@ -240,7 +246,9 @@ export class Model {
})).sort(compareFriends); })).sort(compareFriends);
}) })
.catch(e => { .catch(e => {
DEVELOPMENT && console.error(e); if (DEVELOPMENT) {
console.error(e);
}
setTimeout(() => this.fetchFriends(), 5000); setTimeout(() => this.fetchFriends(), 5000);
}); });
} }
@@ -275,7 +283,8 @@ export class Model {
try { try {
const ponyInfo = decompressPonyString(pony.info, true); const ponyInfo = decompressPonyString(pony.info, true);
return { ponyInfo, ...pony }; return { ponyInfo, ...pony };
} catch (e) { }
catch (e) {
this.errorReporter.reportError(e, { ponyInfo: pony.info }); this.errorReporter.reportError(e, { ponyInfo: pony.info });
this.errorReporter.reportError('Pony info reading error', { originalError: isErrorAlike(e) ? e.message: '', ponyInfo: pony.info }); this.errorReporter.reportError('Pony info reading error', { originalError: isErrorAlike(e) ? e.message: '', ponyInfo: pony.info });
throw new Error('Error while reading pony info'); throw new Error('Error while reading pony info');
@@ -283,7 +292,9 @@ export class Model {
} }
selectPony(pony: PonyObject) { selectPony(pony: PonyObject) {
const copy = this.parsePonyObject(pony); const copy = this.parsePonyObject(pony);
copy.ponyInfo && syncLockedPonyInfo(copy.ponyInfo); if (copy.ponyInfo) {
syncLockedPonyInfo(copy.ponyInfo);
}
this._pony = copy; this._pony = copy;
} }
// account // account
@@ -308,7 +319,8 @@ export class Model {
if (isStandalone()) { if (isStandalone()) {
window.open(url); window.open(url);
} else { }
else {
location.href = url; location.href = url;
} }
} }
@@ -394,7 +406,8 @@ export class Model {
if (pony.id) { if (pony.id) {
removeById(this.ponies, pony.id); removeById(this.ponies, pony.id);
} else { }
else {
this.account!.characterCount++; this.account!.characterCount++;
} }
@@ -443,7 +456,8 @@ export class Model {
if (this.account.birthyear) { if (this.account.birthyear) {
age = currentYear - this.account.birthyear; age = currentYear - this.account.birthyear;
} else if (this.account.birthdate) { }
else if (this.account.birthdate) {
const [year, month] = this.account.birthdate.split('-'); const [year, month] = this.account.birthdate.split('-');
const before = parseInt(month, 10) > currentMonth; const before = parseInt(month, 10) > currentMonth;
age = Math.max(0, currentYear - parseInt(year, 10) - (before ? 1 : 0)); age = Math.max(0, currentYear - parseInt(year, 10) - (before ? 1 : 0));
@@ -458,12 +472,15 @@ export class Model {
return observableToPromise(this.http.get<GameStatus>('/api2/game/status', { params })); return observableToPromise(this.http.get<GameStatus>('/api2/game/status', { params }));
} }
join(serverId: string, ponyId: string): Promise<JoinResponse> { join(serverId: string, ponyId: string): Promise<JoinResponse> {
if (this.pending) if (this.pending) {
return Promise.reject(new Error('Joining in progress')); return Promise.reject(new Error('Joining in progress'));
if (!serverId) }
if (!serverId) {
return Promise.reject(new Error('Invalid server ID')); return Promise.reject(new Error('Invalid server ID'));
if (!ponyId) }
if (!ponyId) {
return Promise.reject(new Error('Invalid pony ID')); return Promise.reject(new Error('Invalid pony ID'));
}
this.pending = true; this.pending = true;
@@ -60,7 +60,8 @@ export class ModelSubscriber<T> {
if (subscription.value !== undefined) { if (subscription.value !== undefined) {
callback(subscription.value); callback(subscription.value);
} }
} else { }
else {
this.socket.server.subscribe(this.type, id); this.socket.server.subscribe(this.type, id);
this.subscriptions.set(id, { this.subscriptions.set(id, {
value: this.defaultValue, value: this.defaultValue,
@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import { ErrorHandler, Injectable, Injector, InjectionToken } from '@angular/core'; import { ErrorHandler, Injectable, Injector, InjectionToken } from '@angular/core';
import Rollbar from 'rollbar'; import Rollbar from 'rollbar';
import { version } from '../../client/data'; import { version } from '../../client/data';
@@ -34,7 +35,8 @@ export const RollbarService = new InjectionToken<Rollbar>('rollbar');
export function rollbarFactory() { export function rollbarFactory() {
if (DEVELOPMENT) { if (DEVELOPMENT) {
return undefined; return undefined;
} else { }
else {
const rollbar = Rollbar.init(rollbarConfig); const rollbar = Rollbar.init(rollbarConfig);
rollbar.configure({ checkIgnore: rollbarCheckIgnore }); rollbar.configure({ checkIgnore: rollbarCheckIgnore });
return rollbar; return rollbar;
@@ -25,7 +25,9 @@ export class RollbarErrorReporter extends ErrorReporter {
} }
} }
reportError(error: any, data?: any) { reportError(error: any, data?: any) {
DEVELOPMENT && console.error(error, data); if (DEVELOPMENT) {
console.error(error, data);
}
if (this.rollbar && !isIgnoredError(error)) { if (this.rollbar && !isIgnoredError(error)) {
this.rollbar.error(error, data); this.rollbar.error(error, data);
@@ -32,7 +32,8 @@ export class SettingsService {
if (this.save(settings)) { if (this.save(settings)) {
return Promise.resolve(); return Promise.resolve();
} else { }
else {
return this.model.saveSettings(settings); return this.model.saveSettings(settings);
} }
} }
+20 -10
View File
@@ -9,18 +9,21 @@ export class StorageService {
if (typeof localStorage === 'undefined') { if (typeof localStorage === 'undefined') {
this.data = new Map(); this.data = new Map();
} }
} catch { }
catch {
this.data = new Map(); this.data = new Map();
} }
} }
getItem(key: string) { getItem(key: string) {
if (this.data) { if (this.data) {
return this.data.get(key); return this.data.get(key);
} else { }
else {
try { try {
const value = localStorage.getItem(key); const value = localStorage.getItem(key);
return value == null ? undefined : value; return value == null ? undefined : value;
} catch { }
catch {
return undefined; return undefined;
} }
} }
@@ -29,7 +32,8 @@ export class StorageService {
try { try {
localStorage.setItem(key, data); localStorage.setItem(key, data);
this.data = undefined; this.data = undefined;
} catch { }
catch {
if (!this.data) { if (!this.data) {
this.data = new Map(); this.data = new Map();
} }
@@ -40,25 +44,30 @@ export class StorageService {
removeItem(key: string) { removeItem(key: string) {
if (this.data) { if (this.data) {
this.data.delete(key); this.data.delete(key);
} else { }
else {
try { try {
localStorage.removeItem(key); localStorage.removeItem(key);
} catch { } }
catch { }
} }
} }
clear() { clear() {
if (this.data) { if (this.data) {
this.data.clear(); this.data.clear();
} else { }
else {
try { try {
localStorage.clear(); localStorage.clear();
} catch { } }
catch { }
} }
} }
getJSON<T>(key: string, defaultValue: T): T { getJSON<T>(key: string, defaultValue: T): T {
try { try {
return JSON.parse(this.getItem(key) || ''); return JSON.parse(this.getItem(key) || '');
} catch { }
catch {
return defaultValue; return defaultValue;
} }
} }
@@ -77,7 +86,8 @@ export class StorageService {
setBoolean(key: string, value: boolean) { setBoolean(key: string, value: boolean) {
if (value) { if (value) {
this.setItem(key, 'true'); this.setItem(key, 'true');
} else { }
else {
this.removeItem(key); this.removeItem(key);
} }
} }
@@ -117,7 +117,8 @@ export class ActionBar {
while (actions.length < 5 || (last(actions)!.action !== undefined && actions.length < ACTIONS_LIMIT)) { while (actions.length < 5 || (last(actions)!.action !== undefined && actions.length < ACTIONS_LIMIT)) {
actions.push({ action: undefined }); actions.push({ action: undefined });
} }
} else { }
else {
while (actions.length > 0 && last(actions)!.action === undefined) { while (actions.length > 0 && last(actions)!.action === undefined) {
actions.pop(); actions.pop();
} }
@@ -96,7 +96,9 @@ export class ActionsModal implements OnInit, OnDestroy {
document.body.classList.remove('actions-modal-opened'); document.body.classList.remove('actions-modal-opened');
this.game.editingActions = false; this.game.editingActions = false;
clearInterval(this.interval); clearInterval(this.interval);
this.subscription && this.subscription.unsubscribe(); if (this.subscription) {
this.subscription.unsubscribe();
}
this.close.emit(); // need to emit in case the menu wasn't closed with the Close button this.close.emit(); // need to emit in case the menu wasn't closed with the Close button
this.notify.emit(); this.notify.emit();
} }

Some files were not shown because too many files have changed in this diff Show More