mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-25 22:25:53 +02:00
Revert codestyle changes (#40)
* Revert "7f7efbb94bab8574e42d942ad82d414e007b2970" Code style changes should probably be part of a PR
This commit is contained in:
+489
-489
File diff suppressed because it is too large
Load Diff
@@ -2,100 +2,100 @@ import { saveAs } from 'file-saver';
|
||||
|
||||
/* istanbul ignore next */
|
||||
export let createCanvas = (width: number, height: number): HTMLCanvasElement => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width | 0;
|
||||
canvas.height = height | 0;
|
||||
return canvas;
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width | 0;
|
||||
canvas.height = height | 0;
|
||||
return canvas;
|
||||
};
|
||||
|
||||
/* istanbul ignore next */
|
||||
export let loadImage = (src: string): Promise<HTMLImageElement | ImageBitmap> => {
|
||||
return new Promise<HTMLImageElement>((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.addEventListener('load', () => resolve(img));
|
||||
img.addEventListener('error', () => reject(new Error(`Error loading image (${src})`)));
|
||||
img.src = src;
|
||||
});
|
||||
return new Promise<HTMLImageElement>((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.addEventListener('load', () => resolve(img));
|
||||
img.addEventListener('error', () => reject(new Error(`Error loading image (${src})`)));
|
||||
img.src = src;
|
||||
});
|
||||
};
|
||||
|
||||
/* istanbul ignore next */
|
||||
function canUseImageBitmap() {
|
||||
return typeof fetch === 'function' &&
|
||||
typeof createImageBitmap === 'function' &&
|
||||
!/yabrowser/i.test(navigator.userAgent); // disabled due to yandex browser bug
|
||||
return typeof fetch === 'function' &&
|
||||
typeof createImageBitmap === 'function' &&
|
||||
!/yabrowser/i.test(navigator.userAgent); // disabled due to yandex browser bug
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (canUseImageBitmap()) {
|
||||
loadImage = src => fetch(src)
|
||||
.then(response => response.blob())
|
||||
.then(createImageBitmap);
|
||||
loadImage = src => fetch(src)
|
||||
.then(response => response.blob())
|
||||
.then(createImageBitmap);
|
||||
}
|
||||
|
||||
export function setup(methods: {
|
||||
createCanvas(width: number, height: number): HTMLCanvasElement;
|
||||
loadImage(src: string): Promise<HTMLImageElement>;
|
||||
createCanvas(width: number, height: number): HTMLCanvasElement;
|
||||
loadImage(src: string): Promise<HTMLImageElement>;
|
||||
}) {
|
||||
createCanvas = methods.createCanvas;
|
||||
loadImage = methods.loadImage;
|
||||
createCanvas = methods.createCanvas;
|
||||
loadImage = methods.loadImage;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const getPixelRatio = SERVER ? () => 1 : () => window.devicePixelRatio;
|
||||
|
||||
export function resizeCanvas(canvas: HTMLCanvasElement, width: number, height: number) {
|
||||
if (canvas.width !== width || canvas.height !== height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
if (canvas.width !== width || canvas.height !== height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
export function resizeCanvasWithRatio(canvas: HTMLCanvasElement, width: number, height: number, updateStyle = true) {
|
||||
const ratio = getPixelRatio();
|
||||
const w = Math.round(width * ratio);
|
||||
const h = Math.round(height * ratio);
|
||||
let resized = false;
|
||||
const ratio = getPixelRatio();
|
||||
const w = Math.round(width * ratio);
|
||||
const h = Math.round(height * ratio);
|
||||
let resized = false;
|
||||
|
||||
if (canvas.width !== w || canvas.height !== h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
resized = true;
|
||||
}
|
||||
if (canvas.width !== w || canvas.height !== h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
resized = true;
|
||||
}
|
||||
|
||||
if (updateStyle && (canvas.style.width !== width + 'px' || canvas.style.height !== height + 'px')) {
|
||||
canvas.style.width = width + 'px';
|
||||
canvas.style.height = height + 'px';
|
||||
resized = true;
|
||||
}
|
||||
if (updateStyle && (canvas.style.width !== width + 'px' || canvas.style.height !== height + 'px')) {
|
||||
canvas.style.width = width + 'px';
|
||||
canvas.style.height = height + 'px';
|
||||
resized = true;
|
||||
}
|
||||
|
||||
return resized;
|
||||
return resized;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function canvasToSource(canvas: HTMLCanvasElement) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
canvas.toBlob(blob => {
|
||||
if (blob) {
|
||||
resolve(URL.createObjectURL(blob));
|
||||
} else {
|
||||
reject(new Error('Failed to convert canvas'));
|
||||
}
|
||||
});
|
||||
});
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
canvas.toBlob(blob => {
|
||||
if (blob) {
|
||||
resolve(URL.createObjectURL(blob));
|
||||
} else {
|
||||
reject(new Error('Failed to convert canvas'));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function saveCanvas(canvas: HTMLCanvasElement, name: string) {
|
||||
canvas.toBlob(blob => blob && saveAs(blob, name));
|
||||
canvas.toBlob(blob => blob && saveAs(blob, name));
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function disableImageSmoothing(context: CanvasRenderingContext2D) {
|
||||
if ('imageSmoothingEnabled' in context) {
|
||||
context.imageSmoothingEnabled = false;
|
||||
} else {
|
||||
(context as any).webkitImageSmoothingEnabled = false;
|
||||
(context as any).mozImageSmoothingEnabled = false;
|
||||
(context as any).msImageSmoothingEnabled = false;
|
||||
}
|
||||
if ('imageSmoothingEnabled' in context) {
|
||||
context.imageSmoothingEnabled = false;
|
||||
} else {
|
||||
(context as any).webkitImageSmoothingEnabled = false;
|
||||
(context as any).mozImageSmoothingEnabled = false;
|
||||
(context as any).msImageSmoothingEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
+241
-241
@@ -1,8 +1,8 @@
|
||||
import { NgZone } from '@angular/core';
|
||||
import { Method, SocketClient, Bin, getMethods } from 'ag-sockets/dist/browser';
|
||||
import {
|
||||
MapInfo, WorldState, PartyMember, PartyFlags, Action, NotificationFlags, Pony, LeaveReason,
|
||||
SayData, MapState, defaultMapState, Apply, InfoFlags, PonyData, FriendStatusData, WorldMap
|
||||
MapInfo, WorldState, PartyMember, PartyFlags, Action, NotificationFlags, Pony, LeaveReason,
|
||||
SayData, MapState, defaultMapState, Apply, InfoFlags, PonyData, FriendStatusData, WorldMap
|
||||
} from '../common/interfaces';
|
||||
import { hasFlag, findById } from '../common/utils';
|
||||
import { isPony } from '../common/pony';
|
||||
@@ -16,8 +16,8 @@ import { addNotification, removeNotification, markGameAsLoaded, resetGameFields,
|
||||
import { Model } from '../components/services/model';
|
||||
import { decodeUpdate } from '../common/encoders/updateDecoder';
|
||||
import {
|
||||
updatePonyInfoWithPoof, subscribeRegion, handleUpdates, handleUpdateEntity, handleRemoveEntity, handleSays,
|
||||
handleEntityInfo, handleUpdatePonies, filterEntityName, handleUpdateFriends
|
||||
updatePonyInfoWithPoof, subscribeRegion, handleUpdates, handleUpdateEntity, handleRemoveEntity, handleSays,
|
||||
handleEntityInfo, handleUpdatePonies, filterEntityName, handleUpdateFriends
|
||||
} from './handlers';
|
||||
import { nameToHTML } from './emoji';
|
||||
|
||||
@@ -27,278 +27,278 @@ const BinNotificationId = Bin.U16;
|
||||
const BinSayDatas = [BinEntityId, Bin.Str, Bin.U8];
|
||||
|
||||
function findPonyById(map: WorldMap, id: number) {
|
||||
const entity = findEntityById(map, id);
|
||||
return entity && isPony(entity) ? entity : undefined;
|
||||
const entity = findEntityById(map, id);
|
||||
return entity && isPony(entity) ? entity : undefined;
|
||||
}
|
||||
|
||||
export class ClientActions implements SocketClient {
|
||||
constructor(private gameService: GameService, private game: PonyTownGame, private model: Model, private zone: NgZone) {
|
||||
}
|
||||
private apply: Apply = func => this.zone.run(func);
|
||||
connected() {
|
||||
resetGameFields(this.game);
|
||||
this.game.map = createWorldMap();
|
||||
this.game.player = undefined;
|
||||
this.game.joined();
|
||||
this.apply(() => this.gameService.joined());
|
||||
constructor(private gameService: GameService, private game: PonyTownGame, private model: Model, private zone: NgZone) {
|
||||
}
|
||||
private apply: Apply = func => this.zone.run(func);
|
||||
connected() {
|
||||
resetGameFields(this.game);
|
||||
this.game.map = createWorldMap();
|
||||
this.game.player = undefined;
|
||||
this.game.joined();
|
||||
this.apply(() => this.gameService.joined());
|
||||
|
||||
const supportsWasm = typeof WebAssembly !== 'undefined';
|
||||
const info = 0 |
|
||||
(isInIncognitoMode ? InfoFlags.Incognito : 0) |
|
||||
(supportsWasm ? InfoFlags.SupportsWASM : 0) |
|
||||
(supportsLetAndConst() ? InfoFlags.SupportsLetAndConst : 0);
|
||||
const supportsWasm = typeof WebAssembly !== 'undefined';
|
||||
const info = 0 |
|
||||
(isInIncognitoMode ? InfoFlags.Incognito : 0) |
|
||||
(supportsWasm ? InfoFlags.SupportsWASM : 0) |
|
||||
(supportsLetAndConst() ? InfoFlags.SupportsLetAndConst : 0);
|
||||
|
||||
this.game.send(server => server.actionParam2(Action.Info, info));
|
||||
}
|
||||
disconnected() {
|
||||
resetGameFields(this.game);
|
||||
this.apply(() => this.gameService.disconnected());
|
||||
}
|
||||
invalidVersion() {
|
||||
DEVELOPMENT && !TESTS && console.error('Invalid version');
|
||||
}
|
||||
@Method({ binary: [Bin.U32] })
|
||||
queue(place: number) {
|
||||
this.game.placeInQueue = place;
|
||||
}
|
||||
@Method({ binary: [Bin.Obj, Bin.Bool] })
|
||||
worldState(state: WorldState, initial: boolean) {
|
||||
this.game.placeInQueue = 0;
|
||||
this.game.setWorldState(state, initial);
|
||||
}
|
||||
@Method({ binary: [Bin.Obj, Bin.Obj] })
|
||||
mapState(info: MapInfo, state: MapState) {
|
||||
this.game.map = createWorldMap(info, state);
|
||||
this.game.player = undefined;
|
||||
this.game.setupMap();
|
||||
updateMapState(this.game.map, defaultMapState, this.game.map.state);
|
||||
}
|
||||
@Method({ binary: [Bin.Obj] })
|
||||
mapUpdate(state: MapState) {
|
||||
const prevState = this.game.map.state;
|
||||
this.game.map.state = state;
|
||||
updateMapState(this.game.map, prevState, this.game.map.state);
|
||||
}
|
||||
@Method({ binary: [] })
|
||||
mapSwitching() {
|
||||
this.game.loaded = false;
|
||||
this.game.placeInQueue = 0;
|
||||
this.game.send(server => server.actionParam2(Action.Info, info));
|
||||
}
|
||||
disconnected() {
|
||||
resetGameFields(this.game);
|
||||
this.apply(() => this.gameService.disconnected());
|
||||
}
|
||||
invalidVersion() {
|
||||
DEVELOPMENT && !TESTS && console.error('Invalid version');
|
||||
}
|
||||
@Method({ binary: [Bin.U32] })
|
||||
queue(place: number) {
|
||||
this.game.placeInQueue = place;
|
||||
}
|
||||
@Method({ binary: [Bin.Obj, Bin.Bool] })
|
||||
worldState(state: WorldState, initial: boolean) {
|
||||
this.game.placeInQueue = 0;
|
||||
this.game.setWorldState(state, initial);
|
||||
}
|
||||
@Method({ binary: [Bin.Obj, Bin.Obj] })
|
||||
mapState(info: MapInfo, state: MapState) {
|
||||
this.game.map = createWorldMap(info, state);
|
||||
this.game.player = undefined;
|
||||
this.game.setupMap();
|
||||
updateMapState(this.game.map, defaultMapState, this.game.map.state);
|
||||
}
|
||||
@Method({ binary: [Bin.Obj] })
|
||||
mapUpdate(state: MapState) {
|
||||
const prevState = this.game.map.state;
|
||||
this.game.map.state = state;
|
||||
updateMapState(this.game.map, prevState, this.game.map.state);
|
||||
}
|
||||
@Method({ binary: [] })
|
||||
mapSwitching() {
|
||||
this.game.loaded = false;
|
||||
this.game.placeInQueue = 0;
|
||||
|
||||
if (this.game.player) {
|
||||
this.game.player.vx = 0;
|
||||
this.game.player.vy = 0;
|
||||
}
|
||||
}
|
||||
@Method({ binary: [Bin.I32, Bin.I32, Bin.U8Array] })
|
||||
mapTest(width: number, height: number, buffer: Uint8Array) {
|
||||
const data = new Uint32Array(width * height);
|
||||
(new Uint8Array(data.buffer)).set(buffer);
|
||||
this.game.minimap = { width, height, data };
|
||||
}
|
||||
@Method({ binary: [BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U16] })
|
||||
myEntity(id: number, name: string, info: string, characterId: string, crc: number) {
|
||||
this.game.playerId = id;
|
||||
this.game.playerName = name;
|
||||
this.game.playerInfo = info;
|
||||
this.game.playerCRC = crc;
|
||||
if (this.game.player) {
|
||||
this.game.player.vx = 0;
|
||||
this.game.player.vy = 0;
|
||||
}
|
||||
}
|
||||
@Method({ binary: [Bin.I32, Bin.I32, Bin.U8Array] })
|
||||
mapTest(width: number, height: number, buffer: Uint8Array) {
|
||||
const data = new Uint32Array(width * height);
|
||||
(new Uint8Array(data.buffer)).set(buffer);
|
||||
this.game.minimap = { width, height, data };
|
||||
}
|
||||
@Method({ binary: [BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U16] })
|
||||
myEntity(id: number, name: string, info: string, characterId: string, crc: number) {
|
||||
this.game.playerId = id;
|
||||
this.game.playerName = name;
|
||||
this.game.playerInfo = info;
|
||||
this.game.playerCRC = crc;
|
||||
|
||||
const pony = findById(this.model.ponies, characterId);
|
||||
const pony = findById(this.model.ponies, characterId);
|
||||
|
||||
if (pony) {
|
||||
this.model.selectPony(pony);
|
||||
}
|
||||
if (pony) {
|
||||
this.model.selectPony(pony);
|
||||
}
|
||||
|
||||
if (this.game.party) {
|
||||
this.game.party.members.forEach(m => m.self = m.id === id);
|
||||
this.game.onPartyUpdate.next();
|
||||
}
|
||||
if (this.game.party) {
|
||||
this.game.party.members.forEach(m => m.self = m.id === id);
|
||||
this.game.onPartyUpdate.next();
|
||||
}
|
||||
|
||||
const entity = findEntityById(this.game.map, id) as Pony | undefined;
|
||||
const entity = findEntityById(this.game.map, id) as Pony | undefined;
|
||||
|
||||
if (entity) {
|
||||
entity.name = name;
|
||||
updatePonyInfoWithPoof(this.game, entity, info, crc);
|
||||
}
|
||||
if (entity) {
|
||||
entity.name = name;
|
||||
updatePonyInfoWithPoof(this.game, entity, info, crc);
|
||||
}
|
||||
|
||||
this.game.onActionsUpdate.next();
|
||||
}
|
||||
@Method({ binary: [[Bin.U8], [Bin.U8Array], Bin.U8Array, [Bin.U8Array], BinSayDatas] })
|
||||
update(unsubscribes: number[], subscribes: Uint8Array[], updates: Uint8Array | null, regions: Uint8Array[], says: SayData[]) {
|
||||
removeRegions(this.game.map, unsubscribes);
|
||||
this.game.onActionsUpdate.next();
|
||||
}
|
||||
@Method({ binary: [[Bin.U8], [Bin.U8Array], Bin.U8Array, [Bin.U8Array], BinSayDatas] })
|
||||
update(unsubscribes: number[], subscribes: Uint8Array[], updates: Uint8Array | null, regions: Uint8Array[], says: SayData[]) {
|
||||
removeRegions(this.game.map, unsubscribes);
|
||||
|
||||
for (const subscribe of subscribes) {
|
||||
subscribeRegion(this.game, subscribe);
|
||||
}
|
||||
for (const subscribe of subscribes) {
|
||||
subscribeRegion(this.game, subscribe);
|
||||
}
|
||||
|
||||
if (subscribes.length) {
|
||||
markGameAsLoaded(this.game);
|
||||
}
|
||||
if (subscribes.length) {
|
||||
markGameAsLoaded(this.game);
|
||||
}
|
||||
|
||||
if (updates) {
|
||||
handleUpdates(this.game, updates);
|
||||
}
|
||||
if (updates) {
|
||||
handleUpdates(this.game, updates);
|
||||
}
|
||||
|
||||
for (const region of regions) {
|
||||
const { x, y, updates, removes, tiles } = decodeUpdate(region);
|
||||
for (const region of regions) {
|
||||
const { x, y, updates, removes, tiles } = decodeUpdate(region);
|
||||
|
||||
for (const update of updates) {
|
||||
handleUpdateEntity(this.game, update);
|
||||
}
|
||||
for (const update of updates) {
|
||||
handleUpdateEntity(this.game, update);
|
||||
}
|
||||
|
||||
for (const id of removes) {
|
||||
handleRemoveEntity(this.game, id);
|
||||
}
|
||||
for (const id of removes) {
|
||||
handleRemoveEntity(this.game, id);
|
||||
}
|
||||
|
||||
for (const tile of tiles) {
|
||||
setTileAtRegion(this.game.map, x, y, tile.x, tile.y, tile.type);
|
||||
}
|
||||
}
|
||||
for (const tile of tiles) {
|
||||
setTileAtRegion(this.game.map, x, y, tile.x, tile.y, tile.type);
|
||||
}
|
||||
}
|
||||
|
||||
for (const [id, message, type] of says) {
|
||||
handleSays(this.game, id, message, type);
|
||||
}
|
||||
}
|
||||
@Method({ binary: [Bin.F32, Bin.F32, Bin.Bool] })
|
||||
fixPosition(x: number, y: number, safe: boolean) {
|
||||
if (DEVELOPMENT && !TESTS && !safe) {
|
||||
console.error(`fix position (${x.toFixed(2)}, ${y.toFixed(2)})`);
|
||||
}
|
||||
for (const [id, message, type] of says) {
|
||||
handleSays(this.game, id, message, type);
|
||||
}
|
||||
}
|
||||
@Method({ binary: [Bin.F32, Bin.F32, Bin.Bool] })
|
||||
fixPosition(x: number, y: number, safe: boolean) {
|
||||
if (DEVELOPMENT && !TESTS && !safe) {
|
||||
console.error(`fix position (${x.toFixed(2)}, ${y.toFixed(2)})`);
|
||||
}
|
||||
|
||||
const player = this.game.player;
|
||||
const player = this.game.player;
|
||||
|
||||
if (player) {
|
||||
player.x = x;
|
||||
player.y = y;
|
||||
savePlayerPosition();
|
||||
}
|
||||
if (player) {
|
||||
player.x = x;
|
||||
player.y = y;
|
||||
savePlayerPosition();
|
||||
}
|
||||
|
||||
this.game.send(server => server.fixedPosition());
|
||||
}
|
||||
@Method({ binary: [BinEntityId, Bin.U8, Bin.Obj] })
|
||||
actionParam(id: number, action: Action, param: any) {
|
||||
switch (action) {
|
||||
case Action.ACL:
|
||||
if (id === this.game.playerId && param) {
|
||||
setAclCookie(param);
|
||||
}
|
||||
break;
|
||||
case Action.FriendsCRC:
|
||||
this.game.nextFriendsCRC = 0;
|
||||
break;
|
||||
default:
|
||||
DEVELOPMENT && !TESTS && console.error(`actionParam: Invalid action: ${action}`);
|
||||
}
|
||||
}
|
||||
@Method({ binary: [Bin.U8] })
|
||||
left(reason: LeaveReason) {
|
||||
this.game.player = undefined;
|
||||
this.game.map = createWorldMap();
|
||||
this.apply(() => this.gameService.left('clientActions.left', reason));
|
||||
}
|
||||
@Method({ binary: [BinNotificationId, BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U8] })
|
||||
addNotification(id: number, entityId: number, name: string, message: string, note: string, flags: NotificationFlags) {
|
||||
const defaultCharacter = hasFlag(flags, NotificationFlags.Supporter) ? this.game.supporterPony : this.game.offlinePony;
|
||||
const pony = (entityId && findPonyById(this.game.map, entityId)) || defaultCharacter;
|
||||
this.game.send(server => server.fixedPosition());
|
||||
}
|
||||
@Method({ binary: [BinEntityId, Bin.U8, Bin.Obj] })
|
||||
actionParam(id: number, action: Action, param: any) {
|
||||
switch (action) {
|
||||
case Action.ACL:
|
||||
if (id === this.game.playerId && param) {
|
||||
setAclCookie(param);
|
||||
}
|
||||
break;
|
||||
case Action.FriendsCRC:
|
||||
this.game.nextFriendsCRC = 0;
|
||||
break;
|
||||
default:
|
||||
DEVELOPMENT && !TESTS && console.error(`actionParam: Invalid action: ${action}`);
|
||||
}
|
||||
}
|
||||
@Method({ binary: [Bin.U8] })
|
||||
left(reason: LeaveReason) {
|
||||
this.game.player = undefined;
|
||||
this.game.map = createWorldMap();
|
||||
this.apply(() => this.gameService.left('clientActions.left', reason));
|
||||
}
|
||||
@Method({ binary: [BinNotificationId, BinEntityId, Bin.Str, Bin.Str, Bin.Str, Bin.U8] })
|
||||
addNotification(id: number, entityId: number, name: string, message: string, note: string, flags: NotificationFlags) {
|
||||
const defaultCharacter = hasFlag(flags, NotificationFlags.Supporter) ? this.game.supporterPony : this.game.offlinePony;
|
||||
const pony = (entityId && findPonyById(this.game.map, entityId)) || defaultCharacter;
|
||||
|
||||
const filteredName = filterEntityName(this.game, name, hasFlag(flags, NotificationFlags.NameBad));
|
||||
message = message.replace(/#NAME#/g, nameToHTML(filteredName || ''));
|
||||
const filteredName = filterEntityName(this.game, name, hasFlag(flags, NotificationFlags.NameBad));
|
||||
message = message.replace(/#NAME#/g, nameToHTML(filteredName || ''));
|
||||
|
||||
this.apply(() => addNotification(this.game, { id, message, note, pony, flags, open: false, fresh: true }));
|
||||
}
|
||||
@Method({ binary: [BinNotificationId] })
|
||||
removeNotification(id: number) {
|
||||
this.apply(() => removeNotification(this.game, id));
|
||||
}
|
||||
@Method({ binary: [BinEntityId, BinEntityId] })
|
||||
updateSelection(currentId: number, newId: number) {
|
||||
if (isSelected(this.game, currentId)) {
|
||||
this.game.select(newId ? findPonyById(this.game.map, newId) : undefined);
|
||||
}
|
||||
}
|
||||
@Method({ binary: [[BinEntityId, Bin.U8]] })
|
||||
updateParty(party: [number, PartyFlags][] | undefined) {
|
||||
const members = party && party.map<PartyMember>(([id, flags]) => ({
|
||||
id,
|
||||
pony: findPonyById(this.game.map, id) || this.game.fallbackPonies.get(id),
|
||||
self: id === this.game.playerId,
|
||||
leader: hasFlag(flags, PartyFlags.Leader),
|
||||
pending: hasFlag(flags, PartyFlags.Pending),
|
||||
offline: hasFlag(flags, PartyFlags.Offline),
|
||||
}));
|
||||
this.apply(() => addNotification(this.game, { id, message, note, pony, flags, open: false, fresh: true }));
|
||||
}
|
||||
@Method({ binary: [BinNotificationId] })
|
||||
removeNotification(id: number) {
|
||||
this.apply(() => removeNotification(this.game, id));
|
||||
}
|
||||
@Method({ binary: [BinEntityId, BinEntityId] })
|
||||
updateSelection(currentId: number, newId: number) {
|
||||
if (isSelected(this.game, currentId)) {
|
||||
this.game.select(newId ? findPonyById(this.game.map, newId) : undefined);
|
||||
}
|
||||
}
|
||||
@Method({ binary: [[BinEntityId, Bin.U8]] })
|
||||
updateParty(party: [number, PartyFlags][] | undefined) {
|
||||
const members = party && party.map<PartyMember>(([id, flags]) => ({
|
||||
id,
|
||||
pony: findPonyById(this.game.map, id) || this.game.fallbackPonies.get(id),
|
||||
self: id === this.game.playerId,
|
||||
leader: hasFlag(flags, PartyFlags.Leader),
|
||||
pending: hasFlag(flags, PartyFlags.Pending),
|
||||
offline: hasFlag(flags, PartyFlags.Offline),
|
||||
}));
|
||||
|
||||
if (members) {
|
||||
const missing = members.filter(p => !p.pony).map(p => p.id);
|
||||
if (members) {
|
||||
const missing = members.filter(p => !p.pony).map(p => p.id);
|
||||
|
||||
if (missing.length) {
|
||||
this.game.send(server => server.getPonies(missing));
|
||||
}
|
||||
}
|
||||
if (missing.length) {
|
||||
this.game.send(server => server.getPonies(missing));
|
||||
}
|
||||
}
|
||||
|
||||
this.apply(() => {
|
||||
this.game.party = updateParty(this.game.party, members);
|
||||
this.game.onPartyUpdate.next();
|
||||
});
|
||||
}
|
||||
@Method({ binary: [[BinEntityId, Bin.Obj, Bin.U8Array, Bin.U8Array, BinEntityPlayerState, Bin.Bool]] })
|
||||
updatePonies(ponies: PonyData[]) {
|
||||
handleUpdatePonies(this.game, ponies);
|
||||
}
|
||||
@Method({ binary: [Bin.Obj, Bin.Bool] })
|
||||
updateFriends(friends: FriendStatusData[], removeMissing: boolean) {
|
||||
handleUpdateFriends(this.game, friends, removeMissing);
|
||||
}
|
||||
@Method({ binary: [BinEntityId, Bin.Str, Bin.U32, Bin.Bool] })
|
||||
entityInfo(id: number, name: string, crc: number, nameBad: boolean) {
|
||||
handleEntityInfo(this.game, id, name, crc, nameBad);
|
||||
}
|
||||
@Method({ binary: [Bin.Obj] })
|
||||
entityList(value: { name: string; x: number; y: number; }[]) {
|
||||
if (DEVELOPMENT || BETA) {
|
||||
const list = value.map(({ name, x, y }) => `${name}(${x.toFixed(2)}, ${y.toFixed(2)})`).join('\n');
|
||||
console.log(`ENTITIES:\n${list}`);
|
||||
}
|
||||
}
|
||||
@Method({ binary: [Bin.Obj] })
|
||||
testPositions(data: { frame: number; x: number | undefined; y: number | undefined; moved: boolean; }[]) {
|
||||
if (DEVELOPMENT) {
|
||||
const round = (x: number) => Math.round(x * 100);
|
||||
const same = (ax = 0, ay = 0, bx = 0, by = 0) => round(ax) === round(bx) && round(ay) === round(by);
|
||||
const fmt = (x: number | undefined) => (x === undefined ? '-' : x.toFixed(2)).padStart(5);
|
||||
this.apply(() => {
|
||||
this.game.party = updateParty(this.game.party, members);
|
||||
this.game.onPartyUpdate.next();
|
||||
});
|
||||
}
|
||||
@Method({ binary: [[BinEntityId, Bin.Obj, Bin.U8Array, Bin.U8Array, BinEntityPlayerState, Bin.Bool]] })
|
||||
updatePonies(ponies: PonyData[]) {
|
||||
handleUpdatePonies(this.game, ponies);
|
||||
}
|
||||
@Method({ binary: [Bin.Obj, Bin.Bool] })
|
||||
updateFriends(friends: FriendStatusData[], removeMissing: boolean) {
|
||||
handleUpdateFriends(this.game, friends, removeMissing);
|
||||
}
|
||||
@Method({ binary: [BinEntityId, Bin.Str, Bin.U32, Bin.Bool] })
|
||||
entityInfo(id: number, name: string, crc: number, nameBad: boolean) {
|
||||
handleEntityInfo(this.game, id, name, crc, nameBad);
|
||||
}
|
||||
@Method({ binary: [Bin.Obj] })
|
||||
entityList(value: { name: string; x: number; y: number; }[]) {
|
||||
if (DEVELOPMENT || BETA) {
|
||||
const list = value.map(({ name, x, y }) => `${name}(${x.toFixed(2)}, ${y.toFixed(2)})`).join('\n');
|
||||
console.log(`ENTITIES:\n${list}`);
|
||||
}
|
||||
}
|
||||
@Method({ binary: [Bin.Obj] })
|
||||
testPositions(data: { frame: number; x: number | undefined; y: number | undefined; moved: boolean; }[]) {
|
||||
if (DEVELOPMENT) {
|
||||
const round = (x: number) => Math.round(x * 100);
|
||||
const same = (ax = 0, ay = 0, bx = 0, by = 0) => round(ax) === round(bx) && round(ay) === round(by);
|
||||
const fmt = (x: number | undefined) => (x === undefined ? '-' : x.toFixed(2)).padStart(5);
|
||||
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
if (data[i - 1].frame !== (data[i].frame - 1)) {
|
||||
data.splice(i, 0, { frame: data[i - 1].frame + 1, x: undefined, y: undefined, moved: false });
|
||||
}
|
||||
}
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
if (data[i - 1].frame !== (data[i].frame - 1)) {
|
||||
data.splice(i, 0, { frame: data[i - 1].frame + 1, x: undefined, y: undefined, moved: false });
|
||||
}
|
||||
}
|
||||
|
||||
const clientIndex = this.game.positions.findIndex(p => p.moved);
|
||||
const serverIndex = data.findIndex(p => p.moved);
|
||||
const offset = serverIndex - clientIndex;
|
||||
const clientIndex = this.game.positions.findIndex(p => p.moved);
|
||||
const serverIndex = data.findIndex(p => p.moved);
|
||||
const offset = serverIndex - clientIndex;
|
||||
|
||||
const dat = data.map((p, i) => {
|
||||
const pt = this.game.positions[i - offset] || { x: undefined, y: undefined };
|
||||
return { frame: p.frame, ax: p.x, ay: p.y, bx: pt.x, by: pt.y, serverMoved: p.moved, clientMoved: pt.moved };
|
||||
});
|
||||
const dat = data.map((p, i) => {
|
||||
const pt = this.game.positions[i - offset] || { x: undefined, y: undefined };
|
||||
return { frame: p.frame, ax: p.x, ay: p.y, bx: pt.x, by: pt.y, serverMoved: p.moved, clientMoved: pt.moved };
|
||||
});
|
||||
|
||||
const log = dat.map(({ frame, ax, ay, bx, by, serverMoved, clientMoved }, i) =>
|
||||
`${frame.toString().padStart(7)} | ` +
|
||||
`${fmt(ax)}, ${fmt(ay)} ${serverMoved ? 'M' : ' '} | ` +
|
||||
`${fmt(bx)}, ${fmt(by)} ${clientMoved ? 'M' : ' '} | ` +
|
||||
`${same(ax, ay, bx, by) ? '= ' : ' '} ` +
|
||||
`${i > 0 && dat[i - 1].frame !== (frame - 1) ? 'I ' : ' '}`)
|
||||
.join('\n');
|
||||
const log = dat.map(({ frame, ax, ay, bx, by, serverMoved, clientMoved }, i) =>
|
||||
`${frame.toString().padStart(7)} | ` +
|
||||
`${fmt(ax)}, ${fmt(ay)} ${serverMoved ? 'M' : ' '} | ` +
|
||||
`${fmt(bx)}, ${fmt(by)} ${clientMoved ? 'M' : ' '} | ` +
|
||||
`${same(ax, ay, bx, by) ? '= ' : ' '} ` +
|
||||
`${i > 0 && dat[i - 1].frame !== (frame - 1) ? 'I ' : ' '}`)
|
||||
.join('\n');
|
||||
|
||||
console.log(
|
||||
` frame | server | client | \n` +
|
||||
`-----------------------------------------------\n` +
|
||||
`${log}`);
|
||||
}
|
||||
}
|
||||
console.log(
|
||||
` frame | server | client | \n` +
|
||||
`-----------------------------------------------\n` +
|
||||
`${log}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (DEVELOPMENT) {
|
||||
getMethods(ClientActions)
|
||||
.filter(m => !m.options.binary)
|
||||
.forEach(m => console.error(`Missing binary encoding for ClientActions.${m.name}()`));
|
||||
getMethods(ClientActions)
|
||||
.filter(m => !m.options.binary)
|
||||
.forEach(m => console.error(`Missing binary encoding for ClientActions.${m.name}()`));
|
||||
}
|
||||
|
||||
@@ -4,31 +4,31 @@ import { ModelTypes } from '../common/adminInterfaces';
|
||||
import { ModelSubscriber } from '../components/services/modelSubscriber';
|
||||
|
||||
export interface ClientUpdate {
|
||||
type: ModelTypes;
|
||||
id: string;
|
||||
update: any;
|
||||
type: ModelTypes;
|
||||
id: string;
|
||||
update: any;
|
||||
}
|
||||
|
||||
export class ClientAdminActions {
|
||||
constructor(private model: AdminModel) {
|
||||
}
|
||||
connected() {
|
||||
this.model.initialize(true);
|
||||
this.model.connectedToSocket();
|
||||
}
|
||||
disconnected() {
|
||||
this.model.updateTitle();
|
||||
}
|
||||
@Method()
|
||||
updates(updates: ClientUpdate[]) {
|
||||
for (const { type, id, update } of updates) {
|
||||
const model = this.model[type] as ModelSubscriber<any>;
|
||||
constructor(private model: AdminModel) {
|
||||
}
|
||||
connected() {
|
||||
this.model.initialize(true);
|
||||
this.model.connectedToSocket();
|
||||
}
|
||||
disconnected() {
|
||||
this.model.updateTitle();
|
||||
}
|
||||
@Method()
|
||||
updates(updates: ClientUpdate[]) {
|
||||
for (const { type, id, update } of updates) {
|
||||
const model = this.model[type] as ModelSubscriber<any>;
|
||||
|
||||
if (model) {
|
||||
model.update(id, update);
|
||||
} else {
|
||||
console.error(`Invalid model type "${type}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (model) {
|
||||
model.update(id, update);
|
||||
} else {
|
||||
console.error(`Invalid model type "${type}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+295
-295
@@ -1,11 +1,11 @@
|
||||
import { clamp } from 'lodash';
|
||||
import {
|
||||
SocialSite, SocialSiteInfo, Eye, Muzzle, Iris, ExpressionExtra, Expression, ServerInfo, ServerFeatureFlags,
|
||||
AccountData, AccountDataFlags
|
||||
SocialSite, SocialSiteInfo, Eye, Muzzle, Iris, ExpressionExtra, Expression, ServerInfo, ServerFeatureFlags,
|
||||
AccountData, AccountDataFlags
|
||||
} from '../common/interfaces';
|
||||
import {
|
||||
PLAYER_NAME_MAX_LENGTH, SAY_MAX_LENGTH, SAYS_TIME_MIN, SAYS_TIME_MAX, isChatlogRangeUnlimited, SUPPORTER_REWARDS,
|
||||
PAST_SUPPORTER_REWARDS
|
||||
PLAYER_NAME_MAX_LENGTH, SAY_MAX_LENGTH, SAYS_TIME_MIN, SAYS_TIME_MAX, isChatlogRangeUnlimited, SUPPORTER_REWARDS,
|
||||
PAST_SUPPORTER_REWARDS
|
||||
} from '../common/constants';
|
||||
import { matcher, isSurrogate, fromSurrogate, isLowSurrogate } from '../common/stringUtils';
|
||||
import { oauthProviders } from './data';
|
||||
@@ -18,85 +18,85 @@ export const matchCyrillic = /[\u0400-\u04FF]/g;
|
||||
export const containsCyrillic = matcher(matchCyrillic);
|
||||
|
||||
const otherValid = [
|
||||
'♂♀⚲⚥⚧☿♁⚨⚩⚦⚢⚣⚤', // gender symbols
|
||||
'™®♥♦♣♠❥♡♢♤♧ღஐ·´°•◦✿❀◆◇◈◉◊。¥€«»,:■□—', // other
|
||||
'〈〉「」『』【】《》♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼№●○◌★☆✰✦✧▪▫・', // other 2
|
||||
'\u1160\u3000\u3164', // spaces (replaced later)
|
||||
'♂♀⚲⚥⚧☿♁⚨⚩⚦⚢⚣⚤', // gender symbols
|
||||
'™®♥♦♣♠❥♡♢♤♧ღஐ·´°•◦✿❀◆◇◈◉◊。¥€«»,:■□—', // other
|
||||
'〈〉「」『』【】《》♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼№●○◌★☆✰✦✧▪▫・', // other 2
|
||||
'\u1160\u3000\u3164', // spaces (replaced later)
|
||||
].join('').split('').reduce((set, c) => (set.add(c.charCodeAt(0)), set), new Set<number>());
|
||||
|
||||
export function isValid(c: number): boolean {
|
||||
return (c >= 0x0020 && c <= 0x007e) // latin
|
||||
|| (c >= 0x00a0 && c <= 0x00ff) // latin 1 supplement
|
||||
|| (c >= 0x0100 && c <= 0x017F) // Latin Extended-A
|
||||
|| (c >= 0x0180 && c <= 0x024F) // Latin Extended-B
|
||||
|| (c >= 0x1e00 && c <= 0x1eff) // Latin Extended Additional
|
||||
|| (c >= 0x0370 && c <= 0x03FF) // Greek and Coptic
|
||||
|| (c >= 0x0400 && c <= 0x0481) || (c >= 0x048A && c <= 0x04FF) // cyrillic
|
||||
|| (c >= 0x3041 && c <= 0x3096) // hiragana
|
||||
|| (c >= 0x30A0 && c <= 0x30FF) // hatakana
|
||||
|| (c >= 0x3400 && c <= 0x4DB5) || (c >= 0x4E00 && c <= 0x9FCB) || (c >= 0xF900 && c <= 0xFA6A) // kanji
|
||||
|| (c >= 0x2F00 && c <= 0x2FDF) // Kangxi Radicals
|
||||
|| (c >= 0x3000 && c <= 0x302D) // CJK Symbols and Punctuation
|
||||
|| (c >= 0x1D00 && c <= 0x1D7F) // Phonetic Extensions
|
||||
|| (c >= 0x0250 && c <= 0x02AF) // IPA Extensions
|
||||
|| (c >= 0xA720 && c <= 0xA7FF) // Latin Extended-D
|
||||
|| (c >= 0x0E00 && c <= 0x0E7F) // Thai
|
||||
|| (c >= 0xff01 && c <= 0xff5e) // Romaji (replaced later)
|
||||
|| (c >= 0x2200 && c <= 0x22FF) // Mathematical Operators
|
||||
|| (c >= 0x25A0 && c <= 0x25FF) // Geometric Shapes
|
||||
|| (c >= 0x2600 && c <= 0x26ff) || (c >= 0x2700 && c <= 0x27bf) || (c >= 0x2b00 && c <= 0x2bef) // emoji
|
||||
|| (c >= 0x1f600 && c <= 0x1f64f) || (c >= 0x1f680 && c <= 0x1f6f6) || (c >= 0x1f300 && c <= 0x1f5ff) // emoji
|
||||
|| (c >= 0x231a && c <= 0x231b) || (c >= 0x23e9 && c <= 0x23fa) // emoji
|
||||
|| (c >= 0x1f900 && c <= 0x1f9ff) // Supplemental Symbols and Pictographs
|
||||
|| otherValid.has(c) // other symbols
|
||||
;
|
||||
return (c >= 0x0020 && c <= 0x007e) // latin
|
||||
|| (c >= 0x00a0 && c <= 0x00ff) // latin 1 supplement
|
||||
|| (c >= 0x0100 && c <= 0x017F) // Latin Extended-A
|
||||
|| (c >= 0x0180 && c <= 0x024F) // Latin Extended-B
|
||||
|| (c >= 0x1e00 && c <= 0x1eff) // Latin Extended Additional
|
||||
|| (c >= 0x0370 && c <= 0x03FF) // Greek and Coptic
|
||||
|| (c >= 0x0400 && c <= 0x0481) || (c >= 0x048A && c <= 0x04FF) // cyrillic
|
||||
|| (c >= 0x3041 && c <= 0x3096) // hiragana
|
||||
|| (c >= 0x30A0 && c <= 0x30FF) // hatakana
|
||||
|| (c >= 0x3400 && c <= 0x4DB5) || (c >= 0x4E00 && c <= 0x9FCB) || (c >= 0xF900 && c <= 0xFA6A) // kanji
|
||||
|| (c >= 0x2F00 && c <= 0x2FDF) // Kangxi Radicals
|
||||
|| (c >= 0x3000 && c <= 0x302D) // CJK Symbols and Punctuation
|
||||
|| (c >= 0x1D00 && c <= 0x1D7F) // Phonetic Extensions
|
||||
|| (c >= 0x0250 && c <= 0x02AF) // IPA Extensions
|
||||
|| (c >= 0xA720 && c <= 0xA7FF) // Latin Extended-D
|
||||
|| (c >= 0x0E00 && c <= 0x0E7F) // Thai
|
||||
|| (c >= 0xff01 && c <= 0xff5e) // Romaji (replaced later)
|
||||
|| (c >= 0x2200 && c <= 0x22FF) // Mathematical Operators
|
||||
|| (c >= 0x25A0 && c <= 0x25FF) // Geometric Shapes
|
||||
|| (c >= 0x2600 && c <= 0x26ff) || (c >= 0x2700 && c <= 0x27bf) || (c >= 0x2b00 && c <= 0x2bef) // emoji
|
||||
|| (c >= 0x1f600 && c <= 0x1f64f) || (c >= 0x1f680 && c <= 0x1f6f6) || (c >= 0x1f300 && c <= 0x1f5ff) // emoji
|
||||
|| (c >= 0x231a && c <= 0x231b) || (c >= 0x23e9 && c <= 0x23fa) // emoji
|
||||
|| (c >= 0x1f900 && c <= 0x1f9ff) // Supplemental Symbols and Pictographs
|
||||
|| otherValid.has(c) // other symbols
|
||||
;
|
||||
}
|
||||
|
||||
export function isValid2(c: number): boolean {
|
||||
return (c >= 0x2b0 && c <= 0x2ff) // Spacing Modifier Letters
|
||||
|| (c >= 0x531 && c <= 0x556) || (c >= 0x559 && c <= 0x55f) || (c >= 0x561 && c <= 0x587)
|
||||
|| (c >= 0x589 && c <= 0x58a) || (c >= 0x58c && c <= 0x58f) // Armenian
|
||||
|| (c >= 0x591 && c <= 0x5c7) || (c >= 0x5d0 && c <= 0x5ea) || (c >= 0x5f0 && c <= 0x5f4) // Hebrew
|
||||
|| (c >= 0x600 && c <= 0x6ff) // Arabic
|
||||
|| (c >= 0x7c0 && c <= 0x7fa) // NKo
|
||||
|| (c >= 0x900 && c <= 0x97f) // Devanagari
|
||||
|| (c === 0xb90) || (c === 0xb9c) // Tamil
|
||||
|| (c >= 0xc85 && c <= 0xc8c) || (c >= 0xc8e && c <= 0xc90) || (c >= 0xc91 && c <= 0xca8)
|
||||
|| (c >= 0xcaa && c <= 0xcb3) || (c >= 0xcb5 && c <= 0xcb9) || (c >= 0xce6 && c <= 0xcef) // Kannada
|
||||
|| (c >= 0x10a0 && c <= 0x10c5) || (c === 0x10c7) || (c === 0x10cd) || (c >= 0x10d0 && c <= 0x10ff) // Georgian
|
||||
|| (c >= 0x1100 && c <= 0x11ff) || (c >= 0x3130 && c <= 0x318f) || (c >= 0xac00 && c <= 0xd7af) // Hangul
|
||||
|| (c >= 0x1400 && c <= 0x167f) // Unified Canadian Aboriginal Syllabics
|
||||
|| (c >= 0x2010 && c <= 0x2027) || (c >= 0x2030 && c <= 0x205e) // General Punctuation
|
||||
|| (c >= 0x20a0 && c <= 0x20bf) // Currency Symbols
|
||||
|| (c >= 0x2100 && c <= 0x214f) // Letterlike Symbols
|
||||
|| (c >= 0x2150 && c <= 0x218b) // Number Forms
|
||||
|| (c >= 0x2300 && c <= 0x239a) || (c >= 0x23b4 && c <= 0x23fa) // Miscellaneous Technical
|
||||
|| (c >= 0x2500 && c <= 0x257f) // Box Drawing
|
||||
|| (c >= 0x2800 && c <= 0x28ff) // Braille Patterns
|
||||
|| (c >= 0x3000 && c <= 0x303f) // CJK Symbols and Punctuation
|
||||
|| (c >= 0x3105 && c <= 0x312d) // Bopomofo
|
||||
|| (c >= 0xfe30 && c <= 0xfe4f) // CJK Compatibility Forms
|
||||
|| (c >= 0xff01 && c <= 0xffef) // Halfwidth and Fullwidth Forms
|
||||
// || (c >= 0x1f170 && c < 0x1f189) // Enclosed Alphanumeric Supplement [a-z]
|
||||
|| (c >= 0x1f000 && c <= 0x1f02b) // Mahjong Tiles
|
||||
|| (c >= 0x1f0a0 && c <= 0x1f0ae) || (c >= 0x1f0b1 && c <= 0x1f0bf) || (c >= 0x1f0c1 && c <= 0x1f0cf)
|
||||
|| (c >= 0x1f0d1 && c <= 0x1f0df) || (c >= 0x1f0e0 && c <= 0x1f0f5) // Playing Cards
|
||||
|| (c >= 0x1f1e6 && c <= 0x1f1ff) // Enclosed Alphanumeric Supplement (regional indicators)
|
||||
;
|
||||
return (c >= 0x2b0 && c <= 0x2ff) // Spacing Modifier Letters
|
||||
|| (c >= 0x531 && c <= 0x556) || (c >= 0x559 && c <= 0x55f) || (c >= 0x561 && c <= 0x587)
|
||||
|| (c >= 0x589 && c <= 0x58a) || (c >= 0x58c && c <= 0x58f) // Armenian
|
||||
|| (c >= 0x591 && c <= 0x5c7) || (c >= 0x5d0 && c <= 0x5ea) || (c >= 0x5f0 && c <= 0x5f4) // Hebrew
|
||||
|| (c >= 0x600 && c <= 0x6ff) // Arabic
|
||||
|| (c >= 0x7c0 && c <= 0x7fa) // NKo
|
||||
|| (c >= 0x900 && c <= 0x97f) // Devanagari
|
||||
|| (c === 0xb90) || (c === 0xb9c) // Tamil
|
||||
|| (c >= 0xc85 && c <= 0xc8c) || (c >= 0xc8e && c <= 0xc90) || (c >= 0xc91 && c <= 0xca8)
|
||||
|| (c >= 0xcaa && c <= 0xcb3) || (c >= 0xcb5 && c <= 0xcb9) || (c >= 0xce6 && c <= 0xcef) // Kannada
|
||||
|| (c >= 0x10a0 && c <= 0x10c5) || (c === 0x10c7) || (c === 0x10cd) || (c >= 0x10d0 && c <= 0x10ff) // Georgian
|
||||
|| (c >= 0x1100 && c <= 0x11ff) || (c >= 0x3130 && c <= 0x318f) || (c >= 0xac00 && c <= 0xd7af) // Hangul
|
||||
|| (c >= 0x1400 && c <= 0x167f) // Unified Canadian Aboriginal Syllabics
|
||||
|| (c >= 0x2010 && c <= 0x2027) || (c >= 0x2030 && c <= 0x205e) // General Punctuation
|
||||
|| (c >= 0x20a0 && c <= 0x20bf) // Currency Symbols
|
||||
|| (c >= 0x2100 && c <= 0x214f) // Letterlike Symbols
|
||||
|| (c >= 0x2150 && c <= 0x218b) // Number Forms
|
||||
|| (c >= 0x2300 && c <= 0x239a) || (c >= 0x23b4 && c <= 0x23fa) // Miscellaneous Technical
|
||||
|| (c >= 0x2500 && c <= 0x257f) // Box Drawing
|
||||
|| (c >= 0x2800 && c <= 0x28ff) // Braille Patterns
|
||||
|| (c >= 0x3000 && c <= 0x303f) // CJK Symbols and Punctuation
|
||||
|| (c >= 0x3105 && c <= 0x312d) // Bopomofo
|
||||
|| (c >= 0xfe30 && c <= 0xfe4f) // CJK Compatibility Forms
|
||||
|| (c >= 0xff01 && c <= 0xffef) // Halfwidth and Fullwidth Forms
|
||||
// || (c >= 0x1f170 && c < 0x1f189) // Enclosed Alphanumeric Supplement [a-z]
|
||||
|| (c >= 0x1f000 && c <= 0x1f02b) // Mahjong Tiles
|
||||
|| (c >= 0x1f0a0 && c <= 0x1f0ae) || (c >= 0x1f0b1 && c <= 0x1f0bf) || (c >= 0x1f0c1 && c <= 0x1f0cf)
|
||||
|| (c >= 0x1f0d1 && c <= 0x1f0df) || (c >= 0x1f0e0 && c <= 0x1f0f5) // Playing Cards
|
||||
|| (c >= 0x1f1e6 && c <= 0x1f1ff) // Enclosed Alphanumeric Supplement (regional indicators)
|
||||
;
|
||||
}
|
||||
|
||||
function isInvalid(c: number): boolean {
|
||||
return c === 0x1f595 // middle finger emoji
|
||||
|| c === 0x00ad // soft hyphen
|
||||
;
|
||||
return c === 0x1f595 // middle finger emoji
|
||||
|| c === 0x00ad // soft hyphen
|
||||
;
|
||||
}
|
||||
|
||||
function isValidForName(c: number): boolean {
|
||||
return isValid(c) && !isInvalid(c);
|
||||
return isValid(c) && !isInvalid(c);
|
||||
}
|
||||
|
||||
function isValidForMessage(c: number): boolean {
|
||||
return (isValid(c) || isValid2(c)) && !isInvalid(c);
|
||||
return (isValid(c) || isValid2(c)) && !isInvalid(c);
|
||||
}
|
||||
|
||||
export const matchRomaji = /[\uff01-\uff5e]/g;
|
||||
@@ -104,333 +104,333 @@ export const matchRomaji = /[\uff01-\uff5e]/g;
|
||||
const matchOtherWhitespace = /[\u1160\u2800\u3000\u3164\uffa0]+/g;
|
||||
|
||||
export function replaceRomaji(match: string): string {
|
||||
return String.fromCharCode(match.charCodeAt(0) - 0xfee0);
|
||||
return String.fromCharCode(match.charCodeAt(0) - 0xfee0);
|
||||
}
|
||||
|
||||
export function cleanName(name: string | undefined): string {
|
||||
return filterString(name, isValidForName)
|
||||
.replace(matchOtherWhitespace, ' ') // whitespace characters
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(matchRomaji, replaceRomaji)
|
||||
.trim();
|
||||
return filterString(name, isValidForName)
|
||||
.replace(matchOtherWhitespace, ' ') // whitespace characters
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(matchRomaji, replaceRomaji)
|
||||
.trim();
|
||||
}
|
||||
|
||||
export function cleanMessage(text: string | undefined): string {
|
||||
return filterString(text, isValidForMessage)
|
||||
.replace(matchOtherWhitespace, ' ') // whitespace characters
|
||||
.replace(/[\r\n]/g, '')
|
||||
.replace(matchRomaji, replaceRomaji)
|
||||
.trim()
|
||||
.substr(0, SAY_MAX_LENGTH);
|
||||
return filterString(text, isValidForMessage)
|
||||
.replace(matchOtherWhitespace, ' ') // whitespace characters
|
||||
.replace(/[\r\n]/g, '')
|
||||
.replace(matchRomaji, replaceRomaji)
|
||||
.trim()
|
||||
.substr(0, SAY_MAX_LENGTH);
|
||||
}
|
||||
|
||||
export function filterString(value: string | undefined, filter: (code: number) => boolean): string {
|
||||
value = value || '';
|
||||
value = value || '';
|
||||
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
let code = value.charCodeAt(i);
|
||||
let size = 1;
|
||||
let invalidSurrogate = false;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
let code = value.charCodeAt(i);
|
||||
let size = 1;
|
||||
let invalidSurrogate = false;
|
||||
|
||||
if (isSurrogate(code) && (i + 1) < value.length) {
|
||||
const extra = value.charCodeAt(i + 1);
|
||||
if (isSurrogate(code) && (i + 1) < value.length) {
|
||||
const extra = value.charCodeAt(i + 1);
|
||||
|
||||
if (isLowSurrogate(extra)) {
|
||||
code = fromSurrogate(code, extra);
|
||||
i++;
|
||||
size++;
|
||||
} else {
|
||||
invalidSurrogate = true;
|
||||
}
|
||||
}
|
||||
if (isLowSurrogate(extra)) {
|
||||
code = fromSurrogate(code, extra);
|
||||
i++;
|
||||
size++;
|
||||
} else {
|
||||
invalidSurrogate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidSurrogate || !filter(code)) {
|
||||
i -= size;
|
||||
value = value.substr(0, i + 1) + value.substr(i + size + 1);
|
||||
}
|
||||
}
|
||||
if (invalidSurrogate || !filter(code)) {
|
||||
i -= size;
|
||||
value = value.substr(0, i + 1) + value.substr(i + size + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
return value;
|
||||
}
|
||||
|
||||
export function validatePonyName(name: string | undefined): boolean {
|
||||
return !!name && !!name.length && name.length <= PLAYER_NAME_MAX_LENGTH && !/^[.,_-]+$/.test(name);
|
||||
return !!name && !!name.length && name.length <= PLAYER_NAME_MAX_LENGTH && !/^[.,_-]+$/.test(name);
|
||||
}
|
||||
|
||||
export function toSocialSiteInfo({ id, name, url, provider }: SocialSite): SocialSiteInfo {
|
||||
const oauth = oauthProviders.find(p => p.id === provider);
|
||||
const oauth = oauthProviders.find(p => p.id === provider);
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
url,
|
||||
icon: oauth && oauth.id,
|
||||
color: oauth && oauth.color,
|
||||
};
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
url,
|
||||
icon: oauth && oauth.id,
|
||||
color: oauth && oauth.color,
|
||||
};
|
||||
}
|
||||
|
||||
function isMultipleMatch(message: string, last: string): boolean {
|
||||
const minMessageLength = 4;
|
||||
const minMessageLength = 4;
|
||||
|
||||
if (message.length >= minMessageLength && last.length >= minMessageLength) {
|
||||
let current = last;
|
||||
if (message.length >= minMessageLength && last.length >= minMessageLength) {
|
||||
let current = last;
|
||||
|
||||
while (current.length < message.length) {
|
||||
current += last;
|
||||
}
|
||||
while (current.length < message.length) {
|
||||
current += last;
|
||||
}
|
||||
|
||||
return message === current.substr(0, SAY_MAX_LENGTH);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return message === current.substr(0, SAY_MAX_LENGTH);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function checkTrailing(message: string, last: string) {
|
||||
return message.indexOf(last) === 0 && (message.length - last.length) < 3;
|
||||
return message.indexOf(last) === 0 && (message.length - last.length) < 3;
|
||||
}
|
||||
|
||||
function isTrailingMatch(message: string, last: string) {
|
||||
const minMessageLength = 5;
|
||||
const minMessageLength = 5;
|
||||
|
||||
if (message.length > last.length && last.length > minMessageLength) {
|
||||
return checkTrailing(message, last);
|
||||
} else if (message.length < last.length && message.length > minMessageLength) {
|
||||
return checkTrailing(last, message);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (message.length > last.length && last.length > minMessageLength) {
|
||||
return checkTrailing(message, last);
|
||||
} else if (message.length < last.length && message.length > minMessageLength) {
|
||||
return checkTrailing(last, message);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function isSpamMessage(message: string, lastMessages: string[]): boolean {
|
||||
if (!/^\//.test(message) && lastMessages.length) {
|
||||
return lastMessages.some(last => message === last || isMultipleMatch(message, last) || isTrailingMatch(message, last));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (!/^\//.test(message) && lastMessages.length) {
|
||||
return lastMessages.some(last => message === last || isMultipleMatch(message, last) || isTrailingMatch(message, last));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getSaysTime(message: string): number {
|
||||
return SAYS_TIME_MIN + clamp(message.length / SAY_MAX_LENGTH, 0, 1) * (SAYS_TIME_MAX - SAYS_TIME_MIN);
|
||||
return SAYS_TIME_MIN + clamp(message.length / SAY_MAX_LENGTH, 0, 1) * (SAYS_TIME_MAX - SAYS_TIME_MIN);
|
||||
}
|
||||
|
||||
export function createExpression(
|
||||
right: Eye, left: Eye, muzzle: Muzzle, rightIris = Iris.Forward, leftIris = Iris.Forward, extra = ExpressionExtra.None
|
||||
right: Eye, left: Eye, muzzle: Muzzle, rightIris = Iris.Forward, leftIris = Iris.Forward, extra = ExpressionExtra.None
|
||||
): Expression {
|
||||
return { right, left, muzzle, rightIris, leftIris, extra };
|
||||
return { right, left, muzzle, rightIris, leftIris, extra };
|
||||
}
|
||||
|
||||
export const isAndroidBrowser = (() => {
|
||||
const ua = typeof navigator === 'undefined' ? '' : navigator.userAgent;
|
||||
const ua = typeof navigator === 'undefined' ? '' : navigator.userAgent;
|
||||
|
||||
// Android browser
|
||||
// Mozilla/5.0 (Linux; U; Android 4.4.2; es-ar; LG-D375AR Build/KOT49I)
|
||||
// AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Mobile Safari/537.36
|
||||
if (/Android /.test(ua) && /AppleWebKit/.test(ua) && (!/chrome/i.test(ua) || /Chrome\/30\./.test(ua))) {
|
||||
return true;
|
||||
}
|
||||
// Android browser
|
||||
// Mozilla/5.0 (Linux; U; Android 4.4.2; es-ar; LG-D375AR Build/KOT49I)
|
||||
// AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Mobile Safari/537.36
|
||||
if (/Android /.test(ua) && /AppleWebKit/.test(ua) && (!/chrome/i.test(ua) || /Chrome\/30\./.test(ua))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
})();
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const isBrowserOutdated = (() => {
|
||||
const ua = typeof navigator === 'undefined' ? '' : navigator.userAgent;
|
||||
const ua = typeof navigator === 'undefined' ? '' : navigator.userAgent;
|
||||
|
||||
// Safari <= 8
|
||||
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1)
|
||||
// AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25
|
||||
const safari = /Version\/(\d+)\.[0-9.]+ Safari/.exec(ua);
|
||||
// Safari <= 8
|
||||
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1)
|
||||
// AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25
|
||||
const safari = /Version\/(\d+)\.[0-9.]+ Safari/.exec(ua);
|
||||
|
||||
if (safari && parseInt(safari[1], 10) <= 8) {
|
||||
return true;
|
||||
}
|
||||
if (safari && parseInt(safari[1], 10) <= 8) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Android browser
|
||||
// Mozilla/5.0 (Linux; U; Android 4.4.2; es-ar; LG-D375AR Build/KOT49I)
|
||||
// AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Mobile Safari/537.36
|
||||
if (isAndroidBrowser) {
|
||||
return true;
|
||||
}
|
||||
// Android browser
|
||||
// Mozilla/5.0 (Linux; U; Android 4.4.2; es-ar; LG-D375AR Build/KOT49I)
|
||||
// AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Mobile Safari/537.36
|
||||
if (isAndroidBrowser) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!supportsLetAndConst()) {
|
||||
return true;
|
||||
}
|
||||
if (!supportsLetAndConst()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
})();
|
||||
|
||||
export function getLocale() {
|
||||
return (navigator.languages ? navigator.languages[0] : navigator.language) || 'en-US';
|
||||
return (navigator.languages ? navigator.languages[0] : navigator.language) || 'en-US';
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function isLanguage(lang: string) {
|
||||
const languages = navigator.languages || [navigator.language];
|
||||
return languages.some(l => l === lang);
|
||||
const languages = navigator.languages || [navigator.language];
|
||||
return languages.some(l => l === lang);
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function sortServersForRussian(a: ServerInfo, b: ServerInfo) {
|
||||
if (a.flag === 'ru' && a.flag !== b.flag) {
|
||||
return -1;
|
||||
}
|
||||
if (a.flag === 'ru' && a.flag !== b.flag) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (b.flag === 'ru' && a.flag !== b.flag) {
|
||||
return 1;
|
||||
}
|
||||
if (b.flag === 'ru' && a.flag !== b.flag) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return a.id.localeCompare(b.id);
|
||||
return a.id.localeCompare(b.id);
|
||||
}
|
||||
|
||||
export function readFileAsText(file: File) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e: any) => resolve(e.target && e.target.result || '');
|
||||
reader.onerror = () => reject(new Error('Failed to read file'));
|
||||
reader.readAsText(file);
|
||||
});
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e: any) => resolve(e.target && e.target.result || '');
|
||||
reader.onerror = () => reject(new Error('Failed to read file'));
|
||||
reader.readAsText(file);
|
||||
});
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function isFileSaverSupported() {
|
||||
try {
|
||||
return !!new Blob;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return !!new Blob;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export let isInIncognitoMode = false;
|
||||
|
||||
export function setIsIncognitoMode(value: boolean) {
|
||||
isInIncognitoMode = value;
|
||||
isInIncognitoMode = value;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
function checkIncognitoMode(wnd: any) {
|
||||
if (!wnd || !wnd.chrome)
|
||||
return;
|
||||
if (!wnd || !wnd.chrome)
|
||||
return;
|
||||
|
||||
const fs = wnd.RequestFileSystem || wnd.webkitRequestFileSystem;
|
||||
const fs = wnd.RequestFileSystem || wnd.webkitRequestFileSystem;
|
||||
|
||||
if (!fs)
|
||||
return;
|
||||
if (!fs)
|
||||
return;
|
||||
|
||||
fs(wnd.TEMPORARY, 100, () => { }, () => isInIncognitoMode = true);
|
||||
fs(wnd.TEMPORARY, 100, () => { }, () => isInIncognitoMode = true);
|
||||
}
|
||||
|
||||
let focused = true;
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function isFocused() {
|
||||
return focused;
|
||||
return focused;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (typeof window !== 'undefined') {
|
||||
checkIncognitoMode(window);
|
||||
window.addEventListener('focus', () => focused = true);
|
||||
window.addEventListener('blur', () => focused = false);
|
||||
checkIncognitoMode(window);
|
||||
window.addEventListener('focus', () => focused = true);
|
||||
window.addEventListener('blur', () => focused = false);
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function isStandalone() {
|
||||
return !!window.matchMedia('(display-mode: standalone)').matches ||
|
||||
(window.navigator as any).standalone === true; // safari
|
||||
return !!window.matchMedia('(display-mode: standalone)').matches ||
|
||||
(window.navigator as any).standalone === true; // safari
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function supportsLetAndConst() {
|
||||
try {
|
||||
return (new Function('let x = true; return x;'))();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return (new Function('let x = true; return x;'))();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function registerServiceWorker(url: string, onUpdate: () => void) {
|
||||
try {
|
||||
if ('serviceWorker' in navigator && typeof navigator.serviceWorker.register === 'function') {
|
||||
let hadWorker = false;
|
||||
try {
|
||||
if ('serviceWorker' in navigator && typeof navigator.serviceWorker.register === 'function') {
|
||||
let hadWorker = false;
|
||||
|
||||
navigator.serviceWorker.register(url)
|
||||
.then(worker => {
|
||||
hadWorker = !!worker.active;
|
||||
navigator.serviceWorker.register(url)
|
||||
.then(worker => {
|
||||
hadWorker = !!worker.active;
|
||||
|
||||
worker.addEventListener('updatefound', () => {
|
||||
if (hadWorker) {
|
||||
onUpdate();
|
||||
}
|
||||
});
|
||||
});
|
||||
worker.addEventListener('updatefound', () => {
|
||||
if (hadWorker) {
|
||||
onUpdate();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||
if (hadWorker) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||
if (hadWorker) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function unregisterServiceWorker() {
|
||||
if ('serviceWorker' in navigator && typeof navigator.serviceWorker.getRegistrations === 'function') {
|
||||
return navigator.serviceWorker.getRegistrations()
|
||||
.then(registrations => {
|
||||
for (const registration of registrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if ('serviceWorker' in navigator && typeof navigator.serviceWorker.getRegistrations === 'function') {
|
||||
return navigator.serviceWorker.getRegistrations()
|
||||
.then(registrations => {
|
||||
for (const registration of registrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function attachDebugMethod(name: string, method: any) {
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any)[name] = method;
|
||||
}
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any)[name] = method;
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function updateRangeIndicator(range: number | undefined, { player, scale, camera }: PonyTownGame) {
|
||||
const e = document.getElementById('range-indicator')!;
|
||||
const e = document.getElementById('range-indicator')!;
|
||||
|
||||
if (player && !isChatlogRangeUnlimited(range)) {
|
||||
const x = (toScreenX(player.x) - camera.x) * scale;
|
||||
const y = (toScreenY(player.y) - camera.actualY) * scale;
|
||||
const w = toScreenX(range!) * scale * 2;
|
||||
const h = toScreenY(range!) * scale * 2;
|
||||
e.style.width = `${w}px`;
|
||||
e.style.height = `${h}px`;
|
||||
e.style.left = `${-w / 2}px`;
|
||||
e.style.top = `${-h / 2}px`;
|
||||
e.style.transform = `translate3d(${x}px, ${y}px, 0)`;
|
||||
e.style.display = 'block';
|
||||
} else {
|
||||
e.style.display = 'none';
|
||||
}
|
||||
if (player && !isChatlogRangeUnlimited(range)) {
|
||||
const x = (toScreenX(player.x) - camera.x) * scale;
|
||||
const y = (toScreenY(player.y) - camera.actualY) * scale;
|
||||
const w = toScreenX(range!) * scale * 2;
|
||||
const h = toScreenY(range!) * scale * 2;
|
||||
e.style.width = `${w}px`;
|
||||
e.style.height = `${h}px`;
|
||||
e.style.left = `${-w / 2}px`;
|
||||
e.style.top = `${-h / 2}px`;
|
||||
e.style.transform = `translate3d(${x}px, ${y}px, 0)`;
|
||||
e.style.display = 'block';
|
||||
} else {
|
||||
e.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function checkIframeKey(iframeId: string, expectedKey: string) {
|
||||
try {
|
||||
const iframe = document.getElementById(iframeId) as HTMLIFrameElement;
|
||||
const doc = iframe && iframe.contentWindow && iframe.contentWindow.document;
|
||||
const key = doc && doc.body && doc.body.getAttribute('data-key');
|
||||
return key === expectedKey;
|
||||
} catch (e) {
|
||||
if (DEVELOPMENT) {
|
||||
console.error(e);
|
||||
}
|
||||
try {
|
||||
const iframe = document.getElementById(iframeId) as HTMLIFrameElement;
|
||||
const doc = iframe && iframe.contentWindow && iframe.contentWindow.document;
|
||||
const key = doc && doc.body && doc.body.getAttribute('data-key');
|
||||
return key === expectedKey;
|
||||
} catch (e) {
|
||||
if (DEVELOPMENT) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let flags: ServerFeatureFlags = {};
|
||||
@@ -438,17 +438,17 @@ let flags: ServerFeatureFlags = {};
|
||||
export const featureFlagsChanged = new Subject<ServerFeatureFlags>();
|
||||
|
||||
export function initFeatureFlags(newFlags: ServerFeatureFlags) {
|
||||
flags = newFlags;
|
||||
featureFlagsChanged.next(newFlags);
|
||||
flags = newFlags;
|
||||
featureFlagsChanged.next(newFlags);
|
||||
}
|
||||
|
||||
export function hasFeatureFlag(flag: keyof ServerFeatureFlags) {
|
||||
return !!flags[flag];
|
||||
return !!flags[flag];
|
||||
}
|
||||
|
||||
export function hardReload() {
|
||||
unregisterServiceWorker()
|
||||
.then(() => location.reload(true));
|
||||
unregisterServiceWorker()
|
||||
.then(() => location.reload(true));
|
||||
}
|
||||
|
||||
const LOGGING = false;
|
||||
@@ -456,47 +456,47 @@ const LOGGING = false;
|
||||
let logger = (_: string) => { };
|
||||
|
||||
export function initLogger(newLogger: (message: string) => void) {
|
||||
if (LOGGING) {
|
||||
logger = newLogger;
|
||||
}
|
||||
if (LOGGING) {
|
||||
logger = newLogger;
|
||||
}
|
||||
}
|
||||
|
||||
export function log(message: string) {
|
||||
if (LOGGING) {
|
||||
logger(message);
|
||||
}
|
||||
if (LOGGING) {
|
||||
logger(message);
|
||||
}
|
||||
}
|
||||
|
||||
export function isSupporterOrPastSupporter(account: AccountData | undefined) {
|
||||
return !!account && (!!account.supporter || hasFlag(account.flags, AccountDataFlags.PastSupporter));
|
||||
return !!account && (!!account.supporter || hasFlag(account.flags, AccountDataFlags.PastSupporter));
|
||||
}
|
||||
|
||||
export function supporterTitle(account: AccountData | undefined) {
|
||||
if (account && account.supporter) {
|
||||
return `Supporter Tier ${account.supporter}`;
|
||||
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
|
||||
return 'Past supporter';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
if (account && account.supporter) {
|
||||
return `Supporter Tier ${account.supporter}`;
|
||||
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
|
||||
return 'Past supporter';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function supporterClass(account: AccountData | undefined) {
|
||||
if (account && account.supporter) {
|
||||
return `supporter-${account.supporter}`;
|
||||
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
|
||||
return 'supporter-past';
|
||||
} else {
|
||||
return 'd-none';
|
||||
}
|
||||
if (account && account.supporter) {
|
||||
return `supporter-${account.supporter}`;
|
||||
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
|
||||
return 'supporter-past';
|
||||
} else {
|
||||
return 'd-none';
|
||||
}
|
||||
}
|
||||
|
||||
export function supporterRewards(account: AccountData | undefined) {
|
||||
if (account && account.supporter) {
|
||||
return SUPPORTER_REWARDS[account.supporter];
|
||||
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
|
||||
return PAST_SUPPORTER_REWARDS;
|
||||
} else {
|
||||
return SUPPORTER_REWARDS[0];
|
||||
}
|
||||
if (account && account.supporter) {
|
||||
return SUPPORTER_REWARDS[account.supporter];
|
||||
} else if (account && hasFlag(account.flags, AccountDataFlags.PastSupporter)) {
|
||||
return PAST_SUPPORTER_REWARDS;
|
||||
} else {
|
||||
return SUPPORTER_REWARDS[0];
|
||||
}
|
||||
}
|
||||
|
||||
+91
-91
@@ -1,105 +1,105 @@
|
||||
export interface Credit {
|
||||
name: string;
|
||||
title: string;
|
||||
avatarIndex: number;
|
||||
links: string[];
|
||||
name: string;
|
||||
title: string;
|
||||
avatarIndex: number;
|
||||
links: string[];
|
||||
}
|
||||
|
||||
export interface Contributor {
|
||||
name: string;
|
||||
links?: string[];
|
||||
name: string;
|
||||
links?: string[];
|
||||
}
|
||||
|
||||
export interface Contributors {
|
||||
group: string;
|
||||
contributors: Contributor[];
|
||||
group: string;
|
||||
contributors: Contributor[];
|
||||
}
|
||||
|
||||
export const CREDITS: Credit[] = [
|
||||
// example:
|
||||
// {
|
||||
// name: 'Your name',
|
||||
// title: 'Your role on the team',
|
||||
// avatarIndex: 0, // place of the avatar in /assets/images/avatars.jpg
|
||||
// links: ['https://twitter.com/your_twitter_handle'],
|
||||
// },
|
||||
{
|
||||
name: 'Bytewave',
|
||||
title: 'Programmer / Moderator',
|
||||
avatarIndex: 0,
|
||||
links: ['https://twitter.com/BytewaveMLP', 'https://github.com/BytewaveMLP']
|
||||
},
|
||||
{
|
||||
name: 'Cloud Hop',
|
||||
title: 'Programmer / Moderator',
|
||||
avatarIndex: 1,
|
||||
links: ['https://twitter.com/blackhole0173', 'https://github.com/blackhole12']
|
||||
},
|
||||
{
|
||||
name: 'CyberPon3',
|
||||
title: 'Programmer / Moderator',
|
||||
avatarIndex: 2,
|
||||
links: ['https://twitter.com/CyberPon3']
|
||||
},
|
||||
{
|
||||
name: 'NotMyWing',
|
||||
title: 'Programmer / Moderator',
|
||||
avatarIndex: 3,
|
||||
links: ['https://twitter.com/NotMyWing', 'https://github.com/Neeve01']
|
||||
},
|
||||
{
|
||||
name: 'Stubenhocker',
|
||||
title: 'Programmer',
|
||||
avatarIndex: 4,
|
||||
links: ['https://github.com/Stubenhocker1399']
|
||||
},
|
||||
{
|
||||
name: 'Luney',
|
||||
title: 'Programmer',
|
||||
avatarIndex: 5,
|
||||
links: ['https://twitter.com/luneythesnep', 'https://github.com/LunarMist']
|
||||
}
|
||||
// example:
|
||||
// {
|
||||
// name: 'Your name',
|
||||
// title: 'Your role on the team',
|
||||
// avatarIndex: 0, // place of the avatar in /assets/images/avatars.jpg
|
||||
// links: ['https://twitter.com/your_twitter_handle'],
|
||||
// },
|
||||
{
|
||||
name: 'Bytewave',
|
||||
title: 'Programmer / Moderator',
|
||||
avatarIndex: 0,
|
||||
links: ['https://twitter.com/BytewaveMLP', 'https://github.com/BytewaveMLP']
|
||||
},
|
||||
{
|
||||
name: 'Cloud Hop',
|
||||
title: 'Programmer / Moderator',
|
||||
avatarIndex: 1,
|
||||
links: ['https://twitter.com/blackhole0173', 'https://github.com/blackhole12']
|
||||
},
|
||||
{
|
||||
name: 'CyberPon3',
|
||||
title: 'Programmer / Moderator',
|
||||
avatarIndex: 2,
|
||||
links: ['https://twitter.com/CyberPon3']
|
||||
},
|
||||
{
|
||||
name: 'NotMyWing',
|
||||
title: 'Programmer / Moderator',
|
||||
avatarIndex: 3,
|
||||
links: ['https://twitter.com/NotMyWing', 'https://github.com/Neeve01']
|
||||
},
|
||||
{
|
||||
name: 'Stubenhocker',
|
||||
title: 'Programmer',
|
||||
avatarIndex: 4,
|
||||
links: ['https://github.com/Stubenhocker1399']
|
||||
},
|
||||
{
|
||||
name: 'Luney',
|
||||
title: 'Programmer',
|
||||
avatarIndex: 5,
|
||||
links: ['https://twitter.com/luneythesnep', 'https://github.com/LunarMist']
|
||||
}
|
||||
];
|
||||
|
||||
export const CONTRIBUTORS: Contributors[] = [
|
||||
{
|
||||
group: 'Artists & Animators',
|
||||
contributors: [
|
||||
{ name: 'Shino', links: ['https://www.deviantart.com/shinodage'] },
|
||||
{ name: 'ChiraChan', links: ['https://www.deviantart.com/chiramii-chan', 'https://chirachan-art.tumblr.com/'] },
|
||||
{ name: 'Goodly', links: ['https://www.deviantart.com/goodlyay'] },
|
||||
{ name: 'TioRafaJP', links: ['https://www.deviantart.com/tiorafajp', 'https://www.youtube.com/user/RafaelJP2'] },
|
||||
{ name: 'ShareMyShipment', links: ['https://www.deviantart.com/sharemyshipment'] },
|
||||
{ name: 'Velenor', links: ['https://www.deviantart.com/velenor'] },
|
||||
{ name: 'OtakuAP', links: ['https://www.deviantart.com/otakuap'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
group: 'Artists',
|
||||
contributors: [
|
||||
{ name: 'Disastral' },
|
||||
{ name: 'Meno', links: ['https://www.deviantart.com/menojar'] },
|
||||
{ name: 'Paulpeoples', links: ['https://www.deviantart.com/paulpeopless'] },
|
||||
{ name: 'Velvet-Frost', links: ['https://www.deviantart.com/velvet-frost'] },
|
||||
{ name: 'Jet7Wave', links: ['https://www.deviantart.com/jetwave'] },
|
||||
{ name: 'Lalieri', links: ['https://lalieri.tumblr.com/'] },
|
||||
{ name: 'Ruef-bae', links: ['https://www.deviantart.com/ruef-bae'] },
|
||||
{ name: 'Alchemist3rd' },
|
||||
{ name: 'Firecracker' },
|
||||
{ name: 'ZippySqrl', links: ['https://www.deviantart.com/zippysqrl'] },
|
||||
{ name: 'Karnel333' },
|
||||
{ name: 'Wellfugzee' },
|
||||
{ name: 'ScribblesHeart', links: ['https://www.deviantart.com/scribblesdesu'] },
|
||||
{ name: 'dsp2003', links: ['https://dsp2003.tumblr.com/', 'http://www.deviantart.com/dsp2003'] },
|
||||
{ name: 'MysticBlare', links: ['https://twitter.com/MysticBlare'] },
|
||||
{ name: 'Towmacow Waffles', links: ['https://www.deviantart.com/towmacowwaffles'] },
|
||||
{ name: 'OrchidPony', links: ['https://www.deviantart.com/orchidpony'] },
|
||||
{ name: 'Cherry Cerise', links: ['https://www.deviantart.com/cherryceriseart'] },
|
||||
{ name: 'Radio' },
|
||||
{ name: 'Ultimate Fluff' },
|
||||
{ name: 'SC', links: ['https://0somecunt0.tumblr.com/tagged/sfw'] },
|
||||
{ name: 'SailorDolpin', links: ['https://vk.com/id324582699'] },
|
||||
{ name: 'Deeraw', links: ['https://www.deviantart.com/deerdraw', 'https://twitter.com/TheOnlyDeeraw'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
group: 'Artists & Animators',
|
||||
contributors: [
|
||||
{ name: 'Shino', links: ['https://www.deviantart.com/shinodage'] },
|
||||
{ name: 'ChiraChan', links: ['https://www.deviantart.com/chiramii-chan', 'https://chirachan-art.tumblr.com/'] },
|
||||
{ name: 'Goodly', links: ['https://www.deviantart.com/goodlyay'] },
|
||||
{ name: 'TioRafaJP', links: ['https://www.deviantart.com/tiorafajp', 'https://www.youtube.com/user/RafaelJP2'] },
|
||||
{ name: 'ShareMyShipment', links: ['https://www.deviantart.com/sharemyshipment'] },
|
||||
{ name: 'Velenor', links: ['https://www.deviantart.com/velenor'] },
|
||||
{ name: 'OtakuAP', links: ['https://www.deviantart.com/otakuap'] },
|
||||
],
|
||||
},
|
||||
{
|
||||
group: 'Artists',
|
||||
contributors: [
|
||||
{ name: 'Disastral' },
|
||||
{ name: 'Meno', links: ['https://www.deviantart.com/menojar'] },
|
||||
{ name: 'Paulpeoples', links: ['https://www.deviantart.com/paulpeopless'] },
|
||||
{ name: 'Velvet-Frost', links: ['https://www.deviantart.com/velvet-frost'] },
|
||||
{ name: 'Jet7Wave', links: ['https://www.deviantart.com/jetwave'] },
|
||||
{ name: 'Lalieri', links: ['https://lalieri.tumblr.com/'] },
|
||||
{ name: 'Ruef-bae', links: ['https://www.deviantart.com/ruef-bae'] },
|
||||
{ name: 'Alchemist3rd' },
|
||||
{ name: 'Firecracker' },
|
||||
{ name: 'ZippySqrl', links: ['https://www.deviantart.com/zippysqrl'] },
|
||||
{ name: 'Karnel333' },
|
||||
{ name: 'Wellfugzee' },
|
||||
{ name: 'ScribblesHeart', links: ['https://www.deviantart.com/scribblesdesu'] },
|
||||
{ name: 'dsp2003', links: ['https://dsp2003.tumblr.com/', 'http://www.deviantart.com/dsp2003'] },
|
||||
{ name: 'MysticBlare', links: ['https://twitter.com/MysticBlare'] },
|
||||
{ name: 'Towmacow Waffles', links: ['https://www.deviantart.com/towmacowwaffles'] },
|
||||
{ name: 'OrchidPony', links: ['https://www.deviantart.com/orchidpony'] },
|
||||
{ name: 'Cherry Cerise', links: ['https://www.deviantart.com/cherryceriseart'] },
|
||||
{ name: 'Radio' },
|
||||
{ name: 'Ultimate Fluff' },
|
||||
{ name: 'SC', links: ['https://0somecunt0.tumblr.com/tagged/sfw'] },
|
||||
{ name: 'SailorDolpin', links: ['https://vk.com/id324582699'] },
|
||||
{ name: 'Deeraw', links: ['https://www.deviantart.com/deerdraw', 'https://twitter.com/TheOnlyDeeraw'] },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
+25
-25
@@ -4,17 +4,17 @@ import { OAuthProvider } from '../common/interfaces';
|
||||
|
||||
/* istanbul ignore next */
|
||||
function attr(name: string): string | undefined {
|
||||
return typeof document !== 'undefined' ? (document.body.getAttribute(name) || undefined) : undefined;
|
||||
return typeof document !== 'undefined' ? (document.body.getAttribute(name) || undefined) : undefined;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
function data(id: string): string | undefined {
|
||||
const element = typeof document !== 'undefined' ? document.getElementById(id) : undefined;
|
||||
return element ? element.innerHTML : undefined;
|
||||
const element = typeof document !== 'undefined' ? document.getElementById(id) : undefined;
|
||||
return element ? element.innerHTML : undefined;
|
||||
}
|
||||
|
||||
function json<T>(id: string, def: string): T {
|
||||
return JSON.parse(data(id) || def);
|
||||
return JSON.parse(data(id) || def);
|
||||
}
|
||||
|
||||
export let isMobile = false;
|
||||
@@ -31,7 +31,7 @@ export const copyrightName = attr('data-copyright');
|
||||
|
||||
/* istanbul ignore next */
|
||||
export const oauthProviders = json<OAuthProvider[]>('oauth-providers', '[]')
|
||||
.map(a => <OAuthProvider>{ ...a, url: `/auth/${a.id}` });
|
||||
.map(a => <OAuthProvider>{ ...a, url: `/auth/${a.id}` });
|
||||
/* istanbul ignore next */
|
||||
export const signUpProviders = oauthProviders.filter(i => !i.connectOnly);
|
||||
/* istanbul ignore next */
|
||||
@@ -39,35 +39,35 @@ export const signInProviders = oauthProviders.filter(i => i.connectOnly);
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function socketOptions(): ClientOptions {
|
||||
const options = data('socket-options');
|
||||
const options = data('socket-options');
|
||||
|
||||
if (options) {
|
||||
const buffer = toByteArray(options);
|
||||
const reader = createBinaryReader(buffer);
|
||||
return readObject(reader);
|
||||
} else {
|
||||
throw new Error('Missing socket options');
|
||||
}
|
||||
if (options) {
|
||||
const buffer = toByteArray(options);
|
||||
const reader = createBinaryReader(buffer);
|
||||
return readObject(reader);
|
||||
} else {
|
||||
throw new Error('Missing socket options');
|
||||
}
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
function setMobile() {
|
||||
isMobile = true;
|
||||
window.removeEventListener('touchstart', setMobile);
|
||||
document.body.classList.add('is-mobile');
|
||||
isMobile = true;
|
||||
window.removeEventListener('touchstart', setMobile);
|
||||
document.body.classList.add('is-mobile');
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (typeof window !== 'undefined') {
|
||||
if (!/windows/i.test(navigator.userAgent)) {
|
||||
window.addEventListener('touchstart', setMobile);
|
||||
}
|
||||
if (!/windows/i.test(navigator.userAgent)) {
|
||||
window.addEventListener('touchstart', setMobile);
|
||||
}
|
||||
|
||||
if (/Trident/.test(navigator.userAgent)) {
|
||||
document.body.classList.add('is-msie');
|
||||
}
|
||||
if (/Trident/.test(navigator.userAgent)) {
|
||||
document.body.classList.add('is-msie');
|
||||
}
|
||||
|
||||
if (/YaBrowser/.test(navigator.userAgent)) {
|
||||
document.body.classList.add('is-yandex');
|
||||
}
|
||||
if (/YaBrowser/.test(navigator.userAgent)) {
|
||||
document.body.classList.add('is-yandex');
|
||||
}
|
||||
}
|
||||
|
||||
+208
-208
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
Entity, DrawOptions, Camera, PaletteSpriteBatch, SpriteBatch, TileSets, Engine, Pony, WorldMap, EntityState
|
||||
Entity, DrawOptions, Camera, PaletteSpriteBatch, SpriteBatch, TileSets, Engine, Pony, WorldMap, EntityState
|
||||
} from '../common/interfaces';
|
||||
import { isBoundsVisible } from '../common/camera';
|
||||
import { drawBounds, drawPixelText, drawBoundsOutline, drawOutlineRect, drawWorldBounds } from '../graphics/graphicsUtils';
|
||||
@@ -16,282 +16,282 @@ import { timeStart, timeEnd } from './timing';
|
||||
const SELECTED_ENTITY_BOUNDS = withAlphaFloat(ORANGE, 0.5);
|
||||
|
||||
function drawEntities(batch: PaletteSpriteBatch, entities: Entity[], camera: Camera, options: DrawOptions) {
|
||||
const drawHidden = options.drawHidden;
|
||||
let entitiesDrawn = 0;
|
||||
const drawHidden = options.drawHidden;
|
||||
let entitiesDrawn = 0;
|
||||
|
||||
for (const entity of entities) {
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.bounds, entity.x, entity.y)) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntity(batch, entity as Pony, options);
|
||||
entitiesDrawn++;
|
||||
} else if (entity.draw !== undefined) {
|
||||
entity.draw(batch, options);
|
||||
entitiesDrawn++;
|
||||
}
|
||||
} else {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
const pony = entity as Pony;
|
||||
for (const entity of entities) {
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.bounds, entity.x, entity.y)) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntity(batch, entity as Pony, options);
|
||||
entitiesDrawn++;
|
||||
} else if (entity.draw !== undefined) {
|
||||
entity.draw(batch, options);
|
||||
entitiesDrawn++;
|
||||
}
|
||||
} else {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
const pony = entity as Pony;
|
||||
|
||||
if (pony.batch !== undefined) {
|
||||
batch.releaseBatch(pony.batch);
|
||||
pony.batch = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pony.batch !== undefined) {
|
||||
batch.releaseBatch(pony.batch);
|
||||
pony.batch = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entitiesDrawn;
|
||||
return entitiesDrawn;
|
||||
}
|
||||
|
||||
export function drawEntityLights(batch: SpriteBatch, entities: Entity[], camera: Camera, options: DrawOptions) {
|
||||
const drawHidden = options.drawHidden;
|
||||
const drawHidden = options.drawHidden;
|
||||
|
||||
for (const entity of entities) {
|
||||
if (DEVELOPMENT && (entity.type !== PONY_TYPE && !entity.drawLight)) {
|
||||
console.error('Cannot draw entity light', entity);
|
||||
}
|
||||
for (const entity of entities) {
|
||||
if (DEVELOPMENT && (entity.type !== PONY_TYPE && !entity.drawLight)) {
|
||||
console.error('Cannot draw entity light', entity);
|
||||
}
|
||||
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.lightBounds, entity.x, entity.y)) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntityLight(batch, entity as Pony, options);
|
||||
} else {
|
||||
entity.drawLight!(batch, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.lightBounds, entity.x, entity.y)) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntityLight(batch, entity as Pony, options);
|
||||
} else {
|
||||
entity.drawLight!(batch, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function drawEntityLightSprites(batch: SpriteBatch, entities: Entity[], camera: Camera, options: DrawOptions) {
|
||||
const drawHidden = options.drawHidden;
|
||||
const drawHidden = options.drawHidden;
|
||||
|
||||
for (const entity of entities) {
|
||||
if (DEVELOPMENT && (entity.type !== PONY_TYPE && !entity.drawLightSprite)) {
|
||||
console.error('Cannot draw entity light sprite', entity);
|
||||
}
|
||||
for (const entity of entities) {
|
||||
if (DEVELOPMENT && (entity.type !== PONY_TYPE && !entity.drawLightSprite)) {
|
||||
console.error('Cannot draw entity light sprite', entity);
|
||||
}
|
||||
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.lightSpriteBounds, entity.x, entity.y)) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntityLightSprite(batch, entity as Pony, options);
|
||||
} else {
|
||||
entity.drawLightSprite!(batch, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!isHidden(entity) || drawHidden) && isBoundsVisible(camera, entity.lightSpriteBounds, entity.x, entity.y)) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
drawPonyEntityLightSprite(batch, entity as Pony, options);
|
||||
} else {
|
||||
entity.drawLightSprite!(batch, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function hasDrawLight(entity: Entity) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
const pony = entity as Pony;
|
||||
return (pony.ponyState.holding !== undefined && pony.ponyState.holding.drawLight !== undefined) ||
|
||||
((pony.state & EntityState.Magic) !== 0);
|
||||
} else {
|
||||
return entity.drawLight !== undefined;
|
||||
}
|
||||
if (entity.type === PONY_TYPE) {
|
||||
const pony = entity as Pony;
|
||||
return (pony.ponyState.holding !== undefined && pony.ponyState.holding.drawLight !== undefined) ||
|
||||
((pony.state & EntityState.Magic) !== 0);
|
||||
} else {
|
||||
return entity.drawLight !== undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function hasLightSprite(entity: Entity) {
|
||||
if (entity.type === PONY_TYPE) {
|
||||
const pony = entity as Pony;
|
||||
return (pony.ponyState.holding !== undefined && pony.ponyState.holding.drawLightSprite !== undefined);
|
||||
} else {
|
||||
return entity.drawLightSprite !== undefined;
|
||||
}
|
||||
if (entity.type === PONY_TYPE) {
|
||||
const pony = entity as Pony;
|
||||
return (pony.ponyState.holding !== undefined && pony.ponyState.holding.drawLightSprite !== undefined);
|
||||
} else {
|
||||
return entity.drawLightSprite !== undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function drawMap(
|
||||
batch: PaletteSpriteBatch, map: WorldMap, camera: Camera, player: Pony, options: DrawOptions,
|
||||
tileSets: TileSets, selectedEntities: Entity[],
|
||||
batch: PaletteSpriteBatch, map: WorldMap, camera: Camera, player: Pony, options: DrawOptions,
|
||||
tileSets: TileSets, selectedEntities: Entity[],
|
||||
) {
|
||||
TIMING && timeStart('forEachRegion');
|
||||
if (BETA && options.engine === Engine.Whiteness) {
|
||||
batch.drawRect(WHITE, 0, 0, toScreenX(map.width), toScreenY(map.height));
|
||||
} else if (BETA && options.engine === Engine.LayeredTiles) {
|
||||
forEachRegion(map, region => drawTilesNew(batch, region, camera, map, tileSets, options));
|
||||
} else {
|
||||
forEachRegion(map, region => drawTiles(batch, region, camera, map, tileSets, options));
|
||||
}
|
||||
TIMING && timeEnd();
|
||||
TIMING && timeStart('forEachRegion');
|
||||
if (BETA && options.engine === Engine.Whiteness) {
|
||||
batch.drawRect(WHITE, 0, 0, toScreenX(map.width), toScreenY(map.height));
|
||||
} else if (BETA && options.engine === Engine.LayeredTiles) {
|
||||
forEachRegion(map, region => drawTilesNew(batch, region, camera, map, tileSets, options));
|
||||
} else {
|
||||
forEachRegion(map, region => drawTiles(batch, region, camera, map, tileSets, options));
|
||||
}
|
||||
TIMING && timeEnd();
|
||||
|
||||
TIMING && timeStart('sortEntities');
|
||||
sortEntities(map.entitiesDrawable);
|
||||
TIMING && timeEnd();
|
||||
TIMING && timeStart('sortEntities');
|
||||
sortEntities(map.entitiesDrawable);
|
||||
TIMING && timeEnd();
|
||||
|
||||
TIMING && timeStart('drawEntities');
|
||||
const entitiesDrawn = drawEntities(batch, map.entitiesDrawable, camera, options);
|
||||
TIMING && timeEnd();
|
||||
TIMING && timeStart('drawEntities');
|
||||
const entitiesDrawn = drawEntities(batch, map.entitiesDrawable, camera, options);
|
||||
TIMING && timeEnd();
|
||||
|
||||
if (BETA || TOOLS) {
|
||||
forEachRegion(map, region => drawTilesDebugInfo(batch, region, camera, options));
|
||||
}
|
||||
if (BETA || TOOLS) {
|
||||
forEachRegion(map, region => drawTilesDebugInfo(batch, region, camera, options));
|
||||
}
|
||||
|
||||
if (BETA && options.debug.showHelpers) {
|
||||
drawDebugHelpers(batch, map.entities, options);
|
||||
}
|
||||
if (BETA && options.debug.showHelpers) {
|
||||
drawDebugHelpers(batch, map.entities, options);
|
||||
}
|
||||
|
||||
if (BETA) {
|
||||
for (const entity of selectedEntities) {
|
||||
const bounds = getAnyBounds(entity);
|
||||
drawBoundsOutline(batch, entity, bounds, SELECTED_ENTITY_BOUNDS, 2);
|
||||
}
|
||||
}
|
||||
if (BETA) {
|
||||
for (const entity of selectedEntities) {
|
||||
const bounds = getAnyBounds(entity);
|
||||
drawBoundsOutline(batch, entity, bounds, SELECTED_ENTITY_BOUNDS, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (BETA && options.debug.showHelpers) {
|
||||
drawOutlineRect(batch, PURPLE, getInteractBounds(player));
|
||||
drawOutlineRect(batch, 0xff000066, getSitOnBounds(player));
|
||||
}
|
||||
if (BETA && options.debug.showHelpers) {
|
||||
drawOutlineRect(batch, PURPLE, getInteractBounds(player));
|
||||
drawOutlineRect(batch, 0xff000066, getSitOnBounds(player));
|
||||
}
|
||||
|
||||
if (BETA && options.showColliderMap) {
|
||||
drawDebugCollider(batch, map, camera);
|
||||
batch.drawRect(PURPLE, toScreenX(player.x) - 1, toScreenY(player.y), 3, 1);
|
||||
batch.drawRect(PURPLE, toScreenX(player.x), toScreenY(player.y) - 1, 1, 3);
|
||||
}
|
||||
if (BETA && options.showColliderMap) {
|
||||
drawDebugCollider(batch, map, camera);
|
||||
batch.drawRect(PURPLE, toScreenX(player.x) - 1, toScreenY(player.y), 3, 1);
|
||||
batch.drawRect(PURPLE, toScreenX(player.x), toScreenY(player.y) - 1, 1, 3);
|
||||
}
|
||||
|
||||
if (BETA && options.showHeightmap) {
|
||||
drawDebugInWater(batch, map, camera);
|
||||
}
|
||||
if (BETA && options.showHeightmap) {
|
||||
drawDebugInWater(batch, map, camera);
|
||||
}
|
||||
|
||||
return entitiesDrawn;
|
||||
return entitiesDrawn;
|
||||
}
|
||||
|
||||
// debug
|
||||
|
||||
function drawDebugHelpers(batch: PaletteSpriteBatch, entities: Entity[], options: DrawOptions) {
|
||||
const textColor = 0x000000b2;
|
||||
const show = options.debug;
|
||||
const textColor = 0x000000b2;
|
||||
const show = options.debug;
|
||||
|
||||
for (const e of entities) {
|
||||
batch.globalAlpha = 0.3;
|
||||
show.bounds && drawBounds(batch, e, e.bounds, ORANGE);
|
||||
show.cover && drawBounds(batch, e, e.coverBounds, BLUE);
|
||||
show.interact && drawBounds(batch, e, e.interactBounds, PURPLE);
|
||||
show.trigger && drawWorldBounds(batch, e, e.triggerBounds, CYAN);
|
||||
for (const e of entities) {
|
||||
batch.globalAlpha = 0.3;
|
||||
show.bounds && drawBounds(batch, e, e.bounds, ORANGE);
|
||||
show.cover && drawBounds(batch, e, e.coverBounds, BLUE);
|
||||
show.interact && drawBounds(batch, e, e.interactBounds, PURPLE);
|
||||
show.trigger && drawWorldBounds(batch, e, e.triggerBounds, CYAN);
|
||||
|
||||
if (show.collider) {
|
||||
batch.globalAlpha = 0.5;
|
||||
if (show.collider) {
|
||||
batch.globalAlpha = 0.5;
|
||||
|
||||
const x = Math.floor(e.x * tileWidth);
|
||||
const y = Math.floor(e.y * tileHeight);
|
||||
const x = Math.floor(e.x * tileWidth);
|
||||
const y = Math.floor(e.y * tileHeight);
|
||||
|
||||
if (e.colliders !== undefined) {
|
||||
for (const collider of e.colliders) {
|
||||
const x1 = x + collider.x;
|
||||
const x2 = x + collider.x + collider.w;
|
||||
const y1 = y + collider.y;
|
||||
const y2 = y + collider.y + collider.h;
|
||||
batch.drawRect(collider.tall ? RED : HOTPINK, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e.colliders !== undefined) {
|
||||
for (const collider of e.colliders) {
|
||||
const x1 = x + collider.x;
|
||||
const x2 = x + collider.x + collider.w;
|
||||
const y1 = y + collider.y;
|
||||
const y2 = y + collider.y + collider.h;
|
||||
batch.drawRect(collider.tall ? RED : HOTPINK, x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
batch.globalAlpha = 1;
|
||||
batch.drawRect(BLACK, toScreenX(e.x), toScreenY(e.y), 1, 1); // anchor
|
||||
batch.globalAlpha = 1;
|
||||
batch.drawRect(BLACK, toScreenX(e.x), toScreenY(e.y), 1, 1); // anchor
|
||||
|
||||
if (show.id) {
|
||||
drawPixelText(batch, toScreenX(e.x) + 2, toScreenY(e.y) + 2, textColor, e.id.toFixed());
|
||||
}
|
||||
}
|
||||
if (show.id) {
|
||||
drawPixelText(batch, toScreenX(e.x) + 2, toScreenY(e.y) + 2, textColor, e.id.toFixed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawDebugInWater(batch: PaletteSpriteBatch, map: WorldMap, camera: Camera) {
|
||||
const color = withAlphaFloat(ORANGE, 0.4);
|
||||
const color = withAlphaFloat(ORANGE, 0.4);
|
||||
|
||||
forEachRegion(map, region => {
|
||||
const sx = toScreenX(region.x * REGION_SIZE);
|
||||
const sy = toScreenY(region.y * REGION_SIZE);
|
||||
const w = REGION_WIDTH;
|
||||
const h = REGION_HEIGHT;
|
||||
forEachRegion(map, region => {
|
||||
const sx = toScreenX(region.x * REGION_SIZE);
|
||||
const sy = toScreenY(region.y * REGION_SIZE);
|
||||
const w = REGION_WIDTH;
|
||||
const h = REGION_HEIGHT;
|
||||
|
||||
const cameraLeft = camera.x;
|
||||
const cameraRight = camera.x + camera.w;
|
||||
const cameraTop = camera.actualY;
|
||||
const cameraBottom = camera.actualY + camera.h;
|
||||
const cameraLeft = camera.x;
|
||||
const cameraRight = camera.x + camera.w;
|
||||
const cameraTop = camera.actualY;
|
||||
const cameraBottom = camera.actualY + camera.h;
|
||||
|
||||
if (sx > cameraRight || sy > cameraBottom || (sx + w) < cameraLeft || (sy + h) < cameraTop)
|
||||
return;
|
||||
if (sx > cameraRight || sy > cameraBottom || (sx + w) < cameraLeft || (sy + h) < cameraTop)
|
||||
return;
|
||||
|
||||
for (let y = 0; y < h; y++) {
|
||||
if ((sy + y + 1) < cameraTop || (sy + y) > cameraBottom)
|
||||
continue;
|
||||
for (let y = 0; y < h; y++) {
|
||||
if ((sy + y + 1) < cameraTop || (sy + y) > cameraBottom)
|
||||
continue;
|
||||
|
||||
for (let x = 0; x < w; x++) {
|
||||
if ((sx + x + 1) < cameraLeft || (sx + x) > cameraRight)
|
||||
continue;
|
||||
for (let x = 0; x < w; x++) {
|
||||
if ((sx + x + 1) < cameraLeft || (sx + x) > cameraRight)
|
||||
continue;
|
||||
|
||||
const tx = x;
|
||||
const tx = x;
|
||||
|
||||
while (isInWaterAt(map, toWorldX(sx + x + 0.5), toWorldY(sy + y + 0.5)) && x < w) {
|
||||
x++;
|
||||
}
|
||||
while (isInWaterAt(map, toWorldX(sx + x + 0.5), toWorldY(sy + y + 0.5)) && x < w) {
|
||||
x++;
|
||||
}
|
||||
|
||||
if (x > tx) {
|
||||
batch.drawRect(color, sx + tx, sy + y, x - tx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (x > tx) {
|
||||
batch.drawRect(color, sx + tx, sy + y, x - tx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function drawDebugCollider(batch: PaletteSpriteBatch, map: WorldMap, camera: Camera) {
|
||||
const color = withAlphaFloat(PURPLE, 0.4);
|
||||
const color = withAlphaFloat(PURPLE, 0.4);
|
||||
|
||||
forEachRegion(map, ({ x, y, collider }) => {
|
||||
const sx = toScreenX(x * REGION_SIZE);
|
||||
const sy = toScreenY(y * REGION_SIZE);
|
||||
const w = REGION_WIDTH;
|
||||
const h = REGION_HEIGHT;
|
||||
forEachRegion(map, ({ x, y, collider }) => {
|
||||
const sx = toScreenX(x * REGION_SIZE);
|
||||
const sy = toScreenY(y * REGION_SIZE);
|
||||
const w = REGION_WIDTH;
|
||||
const h = REGION_HEIGHT;
|
||||
|
||||
const cameraLeft = camera.x;
|
||||
const cameraRight = camera.x + camera.w;
|
||||
const cameraTop = camera.actualY;
|
||||
const cameraBottom = camera.actualY + camera.h;
|
||||
const cameraLeft = camera.x;
|
||||
const cameraRight = camera.x + camera.w;
|
||||
const cameraTop = camera.actualY;
|
||||
const cameraBottom = camera.actualY + camera.h;
|
||||
|
||||
if (sx > cameraRight || sy > cameraBottom || (sx + w) < cameraLeft || (sy + h) < cameraTop)
|
||||
return;
|
||||
if (sx > cameraRight || sy > cameraBottom || (sx + w) < cameraLeft || (sy + h) < cameraTop)
|
||||
return;
|
||||
|
||||
for (let y = 0; y < h; y++) {
|
||||
if ((sy + y + 1) < cameraTop || (sy + y) > cameraBottom)
|
||||
continue;
|
||||
for (let y = 0; y < h; y++) {
|
||||
if ((sy + y + 1) < cameraTop || (sy + y) > cameraBottom)
|
||||
continue;
|
||||
|
||||
for (let x = 0; x < w; x++) {
|
||||
if ((sx + x + 1) < cameraLeft || (sx + x) > cameraRight)
|
||||
continue;
|
||||
for (let x = 0; x < w; x++) {
|
||||
if ((sx + x + 1) < cameraLeft || (sx + x) > cameraRight)
|
||||
continue;
|
||||
|
||||
const tx = x;
|
||||
const tx = x;
|
||||
|
||||
while (collider[x + y * w] !== 0 && x < w) {
|
||||
x++;
|
||||
}
|
||||
while (collider[x + y * w] !== 0 && x < w) {
|
||||
x++;
|
||||
}
|
||||
|
||||
if (x > tx) {
|
||||
batch.drawRect(color, sx + tx, sy + y, x - tx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (x > tx) {
|
||||
batch.drawRect(color, sx + tx, sy + y, x - tx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function drawDebugRegions(batch: SpriteBatch, map: WorldMap, player: Pony, { w, h }: Camera) {
|
||||
const rw = 10;
|
||||
const rh = 8;
|
||||
const width = rw * map.regionsX;
|
||||
const height = rh * map.regionsY;
|
||||
const x = w - width - 10;
|
||||
const y = h - height - 30;
|
||||
const rw = 10;
|
||||
const rh = 8;
|
||||
const width = rw * map.regionsX;
|
||||
const height = rh * map.regionsY;
|
||||
const x = w - width - 10;
|
||||
const y = h - height - 30;
|
||||
|
||||
for (let i = 0; i < map.regionsY; i++) {
|
||||
for (let j = 0; j < map.regionsX; j++) {
|
||||
if (getRegion(map, j, i)) {
|
||||
const inside = j === Math.floor(player.x / REGION_SIZE) && i === Math.floor(player.y / REGION_SIZE);
|
||||
batch.drawRect(inside ? ORANGE : RED, x + rw * j, y + rh * i, rw, rh);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < map.regionsY; i++) {
|
||||
for (let j = 0; j < map.regionsX; j++) {
|
||||
if (getRegion(map, j, i)) {
|
||||
const inside = j === Math.floor(player.x / REGION_SIZE) && i === Math.floor(player.y / REGION_SIZE);
|
||||
batch.drawRect(inside ? ORANGE : RED, x + rw * j, y + rh * i, rw, rh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i <= map.regionsY; i++) {
|
||||
batch.drawRect(GRAY, x, y + rh * i, width + 1, 1);
|
||||
}
|
||||
for (let i = 0; i <= map.regionsY; i++) {
|
||||
batch.drawRect(GRAY, x, y + rh * i, width + 1, 1);
|
||||
}
|
||||
|
||||
for (let i = 0; i <= map.regionsX; i++) {
|
||||
batch.drawRect(GRAY, x + rw * i, y, 1, height);
|
||||
}
|
||||
for (let i = 0; i <= map.regionsX; i++) {
|
||||
batch.drawRect(GRAY, x + rw * i, y, 1, height);
|
||||
}
|
||||
}
|
||||
|
||||
+132
-132
@@ -7,108 +7,108 @@ import { normalSpriteSheet } from '../generated/sprites';
|
||||
import { includes } from '../common/utils';
|
||||
|
||||
export interface Emoji {
|
||||
names: string[];
|
||||
symbol: string;
|
||||
names: string[];
|
||||
symbol: string;
|
||||
}
|
||||
|
||||
export const emojis: Emoji[] = [
|
||||
// faces
|
||||
['🙂', 'face', 'tiny', 'tinyface', 'slight_smile'],
|
||||
['😵', 'derp', 'dizzy_face'],
|
||||
['😠', 'angry'],
|
||||
['😐', 'neutral', 'neutral_face'],
|
||||
['😑', 'expressionless'],
|
||||
['😆', 'laughing'],
|
||||
['😍', 'heart_eyes'],
|
||||
['😟', 'worried'],
|
||||
['🤔', 'thinking'],
|
||||
['🙃', 'upside_down'],
|
||||
['😈', 'evil', 'smiling_imp'],
|
||||
['👿', 'imp', 'angry_evil'],
|
||||
['👃', 'nose', 'c'],
|
||||
// faces
|
||||
['🙂', 'face', 'tiny', 'tinyface', 'slight_smile'],
|
||||
['😵', 'derp', 'dizzy_face'],
|
||||
['😠', 'angry'],
|
||||
['😐', 'neutral', 'neutral_face'],
|
||||
['😑', 'expressionless'],
|
||||
['😆', 'laughing'],
|
||||
['😍', 'heart_eyes'],
|
||||
['😟', 'worried'],
|
||||
['🤔', 'thinking'],
|
||||
['🙃', 'upside_down'],
|
||||
['😈', 'evil', 'smiling_imp'],
|
||||
['👿', 'imp', 'angry_evil'],
|
||||
['👃', 'nose', 'c'],
|
||||
|
||||
// cat faces
|
||||
['🐱', 'cat'],
|
||||
['😺', 'smiley_cat'],
|
||||
['😸', 'smile_cat'],
|
||||
['😹', 'joy_cat'],
|
||||
['😻', 'heart_eyes_cat'],
|
||||
['😼', 'smirk_cat'],
|
||||
['😽', 'kissing_cat'],
|
||||
['🙀', 'scream_cat'],
|
||||
['😿', 'cryingcat', 'crying_cat_face'],
|
||||
['😾', 'pouting_cat'],
|
||||
// cat faces
|
||||
['🐱', 'cat'],
|
||||
['😺', 'smiley_cat'],
|
||||
['😸', 'smile_cat'],
|
||||
['😹', 'joy_cat'],
|
||||
['😻', 'heart_eyes_cat'],
|
||||
['😼', 'smirk_cat'],
|
||||
['😽', 'kissing_cat'],
|
||||
['🙀', 'scream_cat'],
|
||||
['😿', 'cryingcat', 'crying_cat_face'],
|
||||
['😾', 'pouting_cat'],
|
||||
|
||||
// hearts
|
||||
['❤', 'heart'],
|
||||
['💙', 'blue_heart', 'meno'],
|
||||
['💚', 'green_heart', 'chira'],
|
||||
['💛', 'yellow_heart'],
|
||||
['💜', 'purple_heart'],
|
||||
['🖤', 'black_heart', 'shino'],
|
||||
['💔', 'broken_heart'],
|
||||
['💖', 'sparkling_heart'],
|
||||
['💗', 'heartpulse'],
|
||||
['💕', 'two_hearts'],
|
||||
// hearts
|
||||
['❤', 'heart'],
|
||||
['💙', 'blue_heart', 'meno'],
|
||||
['💚', 'green_heart', 'chira'],
|
||||
['💛', 'yellow_heart'],
|
||||
['💜', 'purple_heart'],
|
||||
['🖤', 'black_heart', 'shino'],
|
||||
['💔', 'broken_heart'],
|
||||
['💖', 'sparkling_heart'],
|
||||
['💗', 'heartpulse'],
|
||||
['💕', 'two_hearts'],
|
||||
|
||||
// food / objects
|
||||
['🥌', 'rock', 'stone'],
|
||||
['🍕', 'pizza'],
|
||||
['🍎', 'apple'],
|
||||
['🍏', 'gapple', 'green_apple'],
|
||||
['🍊', 'orange', 'tangerine'],
|
||||
['🍐', 'pear'],
|
||||
['🥭', 'mango'],
|
||||
['🥕', 'carrot'],
|
||||
['🍇', 'grapes'],
|
||||
['🍌', 'banana'],
|
||||
['⛏', 'pick'],
|
||||
['🥚', 'egg'],
|
||||
['💮', 'flower', 'white_flower'],
|
||||
['🌸', 'cherry_blossom'],
|
||||
['🍬', 'candy'],
|
||||
['🍡', 'candy_cane'],
|
||||
['🍭', 'lollipop'],
|
||||
['⭐', 'star'],
|
||||
['🌟', 'star2'],
|
||||
['🌠', 'shooting_star'],
|
||||
['⚡', 'zap'],
|
||||
['❄', 'snow', 'snowflake'],
|
||||
['⛄', 'snowpony', 'snowman'],
|
||||
['🏀', 'pumpkin'],
|
||||
['🎃', 'jacko', 'jack_o_lantern'],
|
||||
['🌲', 'evergreen_tree', 'pinetree'],
|
||||
['🎄', 'christmas_tree'],
|
||||
['🕯', 'candle'],
|
||||
['🎅', 'santa_hat', 'santa_claus'],
|
||||
['💐', 'holly'],
|
||||
['🌿', 'mistletoe'],
|
||||
['🎲', 'die', 'dice', 'game_die'],
|
||||
['✨', 'sparkles'],
|
||||
['🎁', 'gift', 'present'],
|
||||
['🔥', 'fire'],
|
||||
['🎵', 'musical_note'],
|
||||
['🎶', 'notes'],
|
||||
['🌈', 'rainbow'],
|
||||
['🐾', 'feet', 'paw', 'paws'],
|
||||
['👑', 'crown'],
|
||||
['💎', 'gem'],
|
||||
['☘', 'shamrock', 'clover'],
|
||||
['🍀', 'four_leaf_clover'],
|
||||
['🍪', 'cookie'],
|
||||
// food / objects
|
||||
['🥌', 'rock', 'stone'],
|
||||
['🍕', 'pizza'],
|
||||
['🍎', 'apple'],
|
||||
['🍏', 'gapple', 'green_apple'],
|
||||
['🍊', 'orange', 'tangerine'],
|
||||
['🍐', 'pear'],
|
||||
['🥭', 'mango'],
|
||||
['🥕', 'carrot'],
|
||||
['🍇', 'grapes'],
|
||||
['🍌', 'banana'],
|
||||
['⛏', 'pick'],
|
||||
['🥚', 'egg'],
|
||||
['💮', 'flower', 'white_flower'],
|
||||
['🌸', 'cherry_blossom'],
|
||||
['🍬', 'candy'],
|
||||
['🍡', 'candy_cane'],
|
||||
['🍭', 'lollipop'],
|
||||
['⭐', 'star'],
|
||||
['🌟', 'star2'],
|
||||
['🌠', 'shooting_star'],
|
||||
['⚡', 'zap'],
|
||||
['❄', 'snow', 'snowflake'],
|
||||
['⛄', 'snowpony', 'snowman'],
|
||||
['🏀', 'pumpkin'],
|
||||
['🎃', 'jacko', 'jack_o_lantern'],
|
||||
['🌲', 'evergreen_tree', 'pinetree'],
|
||||
['🎄', 'christmas_tree'],
|
||||
['🕯', 'candle'],
|
||||
['🎅', 'santa_hat', 'santa_claus'],
|
||||
['💐', 'holly'],
|
||||
['🌿', 'mistletoe'],
|
||||
['🎲', 'die', 'dice', 'game_die'],
|
||||
['✨', 'sparkles'],
|
||||
['🎁', 'gift', 'present'],
|
||||
['🔥', 'fire'],
|
||||
['🎵', 'musical_note'],
|
||||
['🎶', 'notes'],
|
||||
['🌈', 'rainbow'],
|
||||
['🐾', 'feet', 'paw', 'paws'],
|
||||
['👑', 'crown'],
|
||||
['💎', 'gem'],
|
||||
['☘', 'shamrock', 'clover'],
|
||||
['🍀', 'four_leaf_clover'],
|
||||
['🍪', 'cookie'],
|
||||
|
||||
// animals
|
||||
['🦋', 'butterfly'],
|
||||
['🦇', 'bat'],
|
||||
['🕷', 'spider'],
|
||||
['👻', 'ghost'],
|
||||
['🐈', 'cat2'],
|
||||
// animals
|
||||
['🦋', 'butterfly'],
|
||||
['🦇', 'bat'],
|
||||
['🕷', 'spider'],
|
||||
['👻', 'ghost'],
|
||||
['🐈', 'cat2'],
|
||||
|
||||
// other
|
||||
['™', 'tm'],
|
||||
['♂', 'male'],
|
||||
['♀', 'female'],
|
||||
['⚧', 'trans', 'transgender'],
|
||||
// other
|
||||
['™', 'tm'],
|
||||
['♂', 'male'],
|
||||
['♀', 'female'],
|
||||
['⚧', 'trans', 'transgender'],
|
||||
].map(createEmoji);
|
||||
|
||||
export const emojiMap = new Map<string, string>();
|
||||
@@ -116,79 +116,79 @@ export const emojiNames = emojis.slice().sort().map(e => `:${e.names[0]}:`);
|
||||
emojis.forEach(e => e.names.forEach(name => emojiMap.set(`:${name}:`, e.symbol)));
|
||||
|
||||
export function findEmoji(name: string): Emoji | undefined {
|
||||
return emojis.find(e => name === e.symbol || includes(e.names, name));
|
||||
return emojis.find(e => name === e.symbol || includes(e.names, name));
|
||||
}
|
||||
|
||||
export function replaceEmojis(text: string | undefined): string {
|
||||
return (text || '').replace(/:[a-z0-9_]+:/ig, match => emojiMap.get(match) || match);
|
||||
return (text || '').replace(/:[a-z0-9_]+:/ig, match => emojiMap.get(match) || match);
|
||||
}
|
||||
|
||||
function createEmoji([symbol, ...names]: string[]): Emoji {
|
||||
return { symbol, names: [...names, ...names.filter(n => /_/.test(n)).map(n => n.replace(/_/g, ''))] };
|
||||
return { symbol, names: [...names, ...names.filter(n => /_/.test(n)).map(n => n.replace(/_/g, ''))] };
|
||||
}
|
||||
|
||||
const emojiImages = new Map<Sprite, string>();
|
||||
const emojiImagePromises = new Map<Sprite, Promise<string>>();
|
||||
|
||||
export function getEmojiImageAsync(sprite: Sprite, callback: (str: string) => void) {
|
||||
const src = emojiImages.get(sprite);
|
||||
const src = emojiImages.get(sprite);
|
||||
|
||||
if (src) {
|
||||
callback(src);
|
||||
return;
|
||||
}
|
||||
if (src) {
|
||||
callback(src);
|
||||
return;
|
||||
}
|
||||
|
||||
const promise = emojiImagePromises.get(sprite);
|
||||
const promise = emojiImagePromises.get(sprite);
|
||||
|
||||
if (promise) {
|
||||
promise.then(callback);
|
||||
return;
|
||||
}
|
||||
if (promise) {
|
||||
promise.then(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
const width = sprite.w + sprite.ox;
|
||||
// const height = sprite.h + sprite.oy;
|
||||
const canvas = drawCanvas(width, 10, normalSpriteSheet, undefined, batch => batch.drawSprite(sprite, WHITE, 0, 0));
|
||||
const newPromise = canvasToSource(canvas);
|
||||
emojiImagePromises.set(sprite, newPromise);
|
||||
const width = sprite.w + sprite.ox;
|
||||
// const height = sprite.h + sprite.oy;
|
||||
const canvas = drawCanvas(width, 10, normalSpriteSheet, undefined, batch => batch.drawSprite(sprite, WHITE, 0, 0));
|
||||
const newPromise = canvasToSource(canvas);
|
||||
emojiImagePromises.set(sprite, newPromise);
|
||||
|
||||
newPromise
|
||||
.then(src => {
|
||||
emojiImages.set(sprite, src);
|
||||
emojiImagePromises.delete(sprite);
|
||||
return src;
|
||||
})
|
||||
.then(callback);
|
||||
newPromise
|
||||
.then(src => {
|
||||
emojiImages.set(sprite, src);
|
||||
emojiImagePromises.delete(sprite);
|
||||
return src;
|
||||
})
|
||||
.then(callback);
|
||||
}
|
||||
|
||||
const emojisRegex = new RegExp(`(${[
|
||||
...emojis.map(e => e.symbol),
|
||||
'♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '⛎',
|
||||
...emojis.map(e => e.symbol),
|
||||
'♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '⛎',
|
||||
].join('|')})`, 'g');
|
||||
|
||||
export function splitEmojis(text: string) {
|
||||
return text.split(emojisRegex);
|
||||
return text.split(emojisRegex);
|
||||
}
|
||||
|
||||
export function hasEmojis(text: string) {
|
||||
return emojisRegex.test(text);
|
||||
return emojisRegex.test(text);
|
||||
}
|
||||
|
||||
export function nameToHTML(name: string) {
|
||||
return escape(name);
|
||||
return escape(name);
|
||||
}
|
||||
|
||||
export interface AutocompleteState {
|
||||
lastEmoji?: string;
|
||||
lastEmoji?: string;
|
||||
}
|
||||
|
||||
const names = emojiNames.slice().sort();
|
||||
|
||||
export function autocompleteMesssage(message: string, shift: boolean, state: AutocompleteState): string {
|
||||
return message.replace(/:[a-z0-9_]+:?$/, match => {
|
||||
state.lastEmoji = state.lastEmoji || match;
|
||||
const matches = names.filter(e => e.indexOf(state.lastEmoji!) === 0);
|
||||
const index = matches.indexOf(match);
|
||||
const offset = index === -1 ? 0 : (index + matches.length + (shift ? -1 : 1)) % matches.length;
|
||||
return matches[offset] || match;
|
||||
});
|
||||
return message.replace(/:[a-z0-9_]+:?$/, match => {
|
||||
state.lastEmoji = state.lastEmoji || match;
|
||||
const matches = names.filter(e => e.indexOf(state.lastEmoji!) === 0);
|
||||
const index = matches.indexOf(match);
|
||||
const offset = index === -1 ? 0 : (index + matches.length + (shift ? -1 : 1)) % matches.length;
|
||||
return matches[offset] || match;
|
||||
});
|
||||
}
|
||||
|
||||
+22
-22
@@ -9,31 +9,31 @@ export let fontMono: SpriteFont;
|
||||
export let fontMonoPal: SpriteFont;
|
||||
|
||||
export function createFonts() {
|
||||
font = createSpriteFont(sprites.font, sprites.emoji, 3);
|
||||
font.lineSpacing = 3;
|
||||
font.letterShiftY = -2;
|
||||
font = createSpriteFont(sprites.font, sprites.emoji, 3);
|
||||
font.lineSpacing = 3;
|
||||
font.letterShiftY = -2;
|
||||
|
||||
fontPal = createSpriteFont(sprites.fontPal, sprites.emojiPal, 3);
|
||||
fontPal.lineSpacing = 3;
|
||||
fontPal.letterShiftY = -2;
|
||||
fontPal = createSpriteFont(sprites.fontPal, sprites.emojiPal, 3);
|
||||
fontPal.lineSpacing = 3;
|
||||
fontPal.letterShiftY = -2;
|
||||
|
||||
fontSmall = createSpriteFont(sprites.fontSmall, [], 2);
|
||||
fontSmall.lineSpacing = 4;
|
||||
fontSmall.letterShiftY = -2;
|
||||
fontSmall.letterHeightReal += 2;
|
||||
fontSmall = createSpriteFont(sprites.fontSmall, [], 2);
|
||||
fontSmall.lineSpacing = 4;
|
||||
fontSmall.letterShiftY = -2;
|
||||
fontSmall.letterHeightReal += 2;
|
||||
|
||||
fontSmallPal = createSpriteFont(sprites.fontSmallPal, [], 2);
|
||||
fontSmallPal.lineSpacing = 4;
|
||||
fontSmallPal.letterShiftY = -2;
|
||||
fontSmallPal.letterHeightReal += 2;
|
||||
fontSmallPal = createSpriteFont(sprites.fontSmallPal, [], 2);
|
||||
fontSmallPal.lineSpacing = 4;
|
||||
fontSmallPal.letterShiftY = -2;
|
||||
fontSmallPal.letterHeightReal += 2;
|
||||
|
||||
fontMono = createSpriteFont(sprites.fontMono, [], 4);
|
||||
fontMono.lineSpacing = 4;
|
||||
fontMono.letterShiftY = -2;
|
||||
fontMono.letterHeightReal += 2;
|
||||
fontMono = createSpriteFont(sprites.fontMono, [], 4);
|
||||
fontMono.lineSpacing = 4;
|
||||
fontMono.letterShiftY = -2;
|
||||
fontMono.letterHeightReal += 2;
|
||||
|
||||
fontMonoPal = createSpriteFont(sprites.fontMonoPal, [], 4);
|
||||
fontMonoPal.lineSpacing = 4;
|
||||
fontMonoPal.letterShiftY = -2;
|
||||
fontMonoPal.letterHeightReal += 2;
|
||||
fontMonoPal = createSpriteFont(sprites.fontMonoPal, [], 4);
|
||||
fontMonoPal.lineSpacing = 4;
|
||||
fontMonoPal.letterShiftY = -2;
|
||||
fontMonoPal.letterHeightReal += 2;
|
||||
}
|
||||
|
||||
+1675
-1675
File diff suppressed because it is too large
Load Diff
+65
-65
@@ -1,89 +1,89 @@
|
||||
export interface Game {
|
||||
fps: number;
|
||||
load(): any;
|
||||
init(): void;
|
||||
update(delta: number, now: number, last: number): void;
|
||||
draw(): void;
|
||||
fps: number;
|
||||
load(): any;
|
||||
init(): void;
|
||||
update(delta: number, now: number, last: number): void;
|
||||
draw(): void;
|
||||
}
|
||||
|
||||
export interface GameLoop {
|
||||
started: Promise<void>;
|
||||
cancel(): void;
|
||||
started: Promise<void>;
|
||||
cancel(): void;
|
||||
}
|
||||
|
||||
let gameLoop: GameLoop | undefined = undefined;
|
||||
|
||||
export function startGameLoop(game: Game, onError = (e: Error) => console.error(e)): GameLoop {
|
||||
let handle: any;
|
||||
let backup: any;
|
||||
let cancelled = false;
|
||||
let handle: any;
|
||||
let backup: any;
|
||||
let cancelled = false;
|
||||
|
||||
let last = Math.round(performance.now());
|
||||
let lastFps = last;
|
||||
let frames = 0;
|
||||
let fps = 0;
|
||||
let last = Math.round(performance.now());
|
||||
let lastFps = last;
|
||||
let frames = 0;
|
||||
let fps = 0;
|
||||
|
||||
function step(now: number, draw: boolean) {
|
||||
if (draw) {
|
||||
handle = requestAnimationFrame(onFrame);
|
||||
}
|
||||
function step(now: number, draw: boolean) {
|
||||
if (draw) {
|
||||
handle = requestAnimationFrame(onFrame);
|
||||
}
|
||||
|
||||
frames++;
|
||||
frames++;
|
||||
|
||||
if ((now - lastFps) > 1000) {
|
||||
fps = frames * 1000 / (now - lastFps);
|
||||
frames = 0;
|
||||
lastFps = now;
|
||||
}
|
||||
if ((now - lastFps) > 1000) {
|
||||
fps = frames * 1000 / (now - lastFps);
|
||||
frames = 0;
|
||||
lastFps = now;
|
||||
}
|
||||
|
||||
try {
|
||||
game.fps = fps;
|
||||
game.update((now - last) / 1000, now, last);
|
||||
try {
|
||||
game.fps = fps;
|
||||
game.update((now - last) / 1000, now, last);
|
||||
|
||||
if (draw) {
|
||||
game.draw();
|
||||
}
|
||||
} catch (e) {
|
||||
onError(e);
|
||||
}
|
||||
if (draw) {
|
||||
game.draw();
|
||||
}
|
||||
} catch (e) {
|
||||
onError(e);
|
||||
}
|
||||
|
||||
last = now;
|
||||
}
|
||||
last = now;
|
||||
}
|
||||
|
||||
function onTimer() {
|
||||
step(Math.round(performance.now()), false);
|
||||
backup = setTimeout(onTimer, 1000 / 10);
|
||||
}
|
||||
function onTimer() {
|
||||
step(Math.round(performance.now()), false);
|
||||
backup = setTimeout(onTimer, 1000 / 10);
|
||||
}
|
||||
|
||||
function onFrame() {
|
||||
clearTimeout(backup);
|
||||
step(Math.round(performance.now()), true);
|
||||
backup = setTimeout(onTimer, 1000 / 10);
|
||||
}
|
||||
function onFrame() {
|
||||
clearTimeout(backup);
|
||||
step(Math.round(performance.now()), true);
|
||||
backup = setTimeout(onTimer, 1000 / 10);
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
cancelAnimationFrame(handle);
|
||||
clearTimeout(backup);
|
||||
cancelled = true;
|
||||
}
|
||||
function cancel() {
|
||||
cancelAnimationFrame(handle);
|
||||
clearTimeout(backup);
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
if (gameLoop) {
|
||||
gameLoop.cancel();
|
||||
}
|
||||
if (gameLoop) {
|
||||
gameLoop.cancel();
|
||||
}
|
||||
|
||||
const started = Promise.resolve()
|
||||
.then(() => game.load())
|
||||
.then(() => {
|
||||
if (cancelled) {
|
||||
throw new Error('Cancelled (loop)');
|
||||
} else {
|
||||
game.init();
|
||||
handle = requestAnimationFrame(onFrame);
|
||||
backup = setTimeout(onTimer, 1000 / 10);
|
||||
}
|
||||
});
|
||||
const started = Promise.resolve()
|
||||
.then(() => game.load())
|
||||
.then(() => {
|
||||
if (cancelled) {
|
||||
throw new Error('Cancelled (loop)');
|
||||
} else {
|
||||
game.init();
|
||||
handle = requestAnimationFrame(onFrame);
|
||||
backup = setTimeout(onTimer, 1000 / 10);
|
||||
}
|
||||
});
|
||||
|
||||
gameLoop = { started, cancel };
|
||||
gameLoop = { started, cancel };
|
||||
|
||||
return gameLoop;
|
||||
return gameLoop;
|
||||
}
|
||||
|
||||
+28
-28
@@ -3,47 +3,47 @@ import { PonyTownGame } from './game';
|
||||
import { removeById } from '../common/utils';
|
||||
|
||||
export function addNotification({ notifications }: PonyTownGame, notification: Notification) {
|
||||
const open = notifications.length === 0;
|
||||
const open = notifications.length === 0;
|
||||
|
||||
notifications.push(notification);
|
||||
notifications.push(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.open = open;
|
||||
notification.fresh = false;
|
||||
}, 500);
|
||||
setTimeout(() => {
|
||||
notification.open = open;
|
||||
notification.fresh = false;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
export function removeNotification({ notifications }: PonyTownGame, id: number) {
|
||||
const notification = removeById(notifications, id);
|
||||
const notification = removeById(notifications, id);
|
||||
|
||||
if (notification && notification.open && notifications.length) {
|
||||
notifications[0].open = true;
|
||||
}
|
||||
if (notification && notification.open && notifications.length) {
|
||||
notifications[0].open = true;
|
||||
}
|
||||
}
|
||||
|
||||
export function resetGameFields(game: PonyTownGame) {
|
||||
game.loaded = false;
|
||||
game.placeInQueue = 0;
|
||||
game.playerId = undefined;
|
||||
game.playerName = undefined;
|
||||
game.playerInfo = undefined;
|
||||
game.playerCRC = undefined;
|
||||
game.party = undefined;
|
||||
game.whisperTo = undefined;
|
||||
game.messageQueue = [];
|
||||
game.lastWhisperFrom = undefined;
|
||||
game.onPartyUpdate.next();
|
||||
game.fallbackPonies.clear();
|
||||
game.loaded = false;
|
||||
game.placeInQueue = 0;
|
||||
game.playerId = undefined;
|
||||
game.playerName = undefined;
|
||||
game.playerInfo = undefined;
|
||||
game.playerCRC = undefined;
|
||||
game.party = undefined;
|
||||
game.whisperTo = undefined;
|
||||
game.messageQueue = [];
|
||||
game.lastWhisperFrom = undefined;
|
||||
game.onPartyUpdate.next();
|
||||
game.fallbackPonies.clear();
|
||||
}
|
||||
|
||||
export function markGameAsLoaded(game: PonyTownGame) {
|
||||
if (!game.loaded) {
|
||||
game.loaded = true;
|
||||
game.fullyLoaded = false;
|
||||
setTimeout(() => game.fullyLoaded = true, 300);
|
||||
}
|
||||
if (!game.loaded) {
|
||||
game.loaded = true;
|
||||
game.fullyLoaded = false;
|
||||
setTimeout(() => game.fullyLoaded = true, 300);
|
||||
}
|
||||
}
|
||||
|
||||
export function isSelected(game: PonyTownGame, id: number) {
|
||||
return game.selected && game.selected.id === id;
|
||||
return game.selected && game.selected.id === id;
|
||||
}
|
||||
|
||||
+558
-558
File diff suppressed because it is too large
Load Diff
+100
-100
@@ -4,171 +4,171 @@ import { font } from './fonts';
|
||||
import { getCharacterSprite } from '../graphics/spriteFont';
|
||||
|
||||
export function createHtmlNodes(value: string | undefined, scale: number): Node[] {
|
||||
return value ? splitEmojis(value).map(x => {
|
||||
const sprite = hasEmojis(x) && font && getCharacterSprite(x, font);
|
||||
return value ? splitEmojis(value).map(x => {
|
||||
const sprite = hasEmojis(x) && font && getCharacterSprite(x, font);
|
||||
|
||||
if (sprite) {
|
||||
const emote = findEmoji(x);
|
||||
const img = document.createElement('img');
|
||||
img.className = 'pixelart';
|
||||
img.style.display = 'inline-block';
|
||||
img.style.visibility = 'hidden';
|
||||
img.style.width = `${(sprite.w + sprite.ox) * scale}px`;
|
||||
img.style.height = `${10 * scale}px`;
|
||||
if (sprite) {
|
||||
const emote = findEmoji(x);
|
||||
const img = document.createElement('img');
|
||||
img.className = 'pixelart';
|
||||
img.style.display = 'inline-block';
|
||||
img.style.visibility = 'hidden';
|
||||
img.style.width = `${(sprite.w + sprite.ox) * scale}px`;
|
||||
img.style.height = `${10 * scale}px`;
|
||||
|
||||
if (emote) {
|
||||
img.setAttribute('aria-label', emote.names[0]);
|
||||
}
|
||||
if (emote) {
|
||||
img.setAttribute('aria-label', emote.names[0]);
|
||||
}
|
||||
|
||||
getEmojiImageAsync(sprite, src => {
|
||||
img.alt = x;
|
||||
img.src = src;
|
||||
img.style.visibility = 'visible';
|
||||
});
|
||||
getEmojiImageAsync(sprite, src => {
|
||||
img.alt = x;
|
||||
img.src = src;
|
||||
img.style.visibility = 'visible';
|
||||
});
|
||||
|
||||
return img;
|
||||
} else {
|
||||
return document.createTextNode(x);
|
||||
}
|
||||
}) : [];
|
||||
return img;
|
||||
} else {
|
||||
return document.createTextNode(x);
|
||||
}
|
||||
}) : [];
|
||||
}
|
||||
|
||||
export function textNode(text: string) {
|
||||
return document.createTextNode(text);
|
||||
return document.createTextNode(text);
|
||||
}
|
||||
|
||||
export function element(
|
||||
tag: string, className?: string, nodes?: (Node | undefined)[], attrs?: Dict<any>, events?: Dict<() => any>
|
||||
tag: string, className?: string, nodes?: (Node | undefined)[], attrs?: Dict<any>, events?: Dict<() => any>
|
||||
) {
|
||||
const element = document.createElement(tag);
|
||||
const element = document.createElement(tag);
|
||||
|
||||
if (className) {
|
||||
element.className = className;
|
||||
}
|
||||
if (className) {
|
||||
element.className = className;
|
||||
}
|
||||
|
||||
if (nodes !== undefined) {
|
||||
appendAllNodes(element, nodes);
|
||||
}
|
||||
if (nodes !== undefined) {
|
||||
appendAllNodes(element, nodes);
|
||||
}
|
||||
|
||||
if (attrs !== undefined) {
|
||||
Object.keys(attrs).forEach(key => element.setAttribute(key, attrs[key]));
|
||||
}
|
||||
if (attrs !== undefined) {
|
||||
Object.keys(attrs).forEach(key => element.setAttribute(key, attrs[key]));
|
||||
}
|
||||
|
||||
if (events !== undefined) {
|
||||
Object.keys(events).forEach(key => element.addEventListener(key, events[key]));
|
||||
}
|
||||
if (events !== undefined) {
|
||||
Object.keys(events).forEach(key => element.addEventListener(key, events[key]));
|
||||
}
|
||||
|
||||
return element;
|
||||
return element;
|
||||
}
|
||||
|
||||
export function appendAllNodes(element: Element, nodes: (Node | undefined)[]) {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
|
||||
if (node !== undefined) {
|
||||
element.appendChild(node);
|
||||
}
|
||||
}
|
||||
if (node !== undefined) {
|
||||
element.appendChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function removeAllNodes(element: Element) {
|
||||
let child: Node | null;
|
||||
let child: Node | null;
|
||||
|
||||
while (child = element.lastChild) {
|
||||
element.removeChild(child);
|
||||
}
|
||||
while (child = element.lastChild) {
|
||||
element.removeChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
export function removeFirstChild(element: HTMLElement) {
|
||||
let child: Node | null;
|
||||
let child: Node | null;
|
||||
|
||||
if (child = element.firstChild) {
|
||||
element.removeChild(child);
|
||||
}
|
||||
if (child = element.firstChild) {
|
||||
element.removeChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
export function removeElement(element: HTMLElement) {
|
||||
element.parentElement && element.parentElement.removeChild(element);
|
||||
element.parentElement && element.parentElement.removeChild(element);
|
||||
}
|
||||
|
||||
export function replaceNodes(element: HTMLElement, text: string) {
|
||||
while (element.lastChild && element.lastChild !== element.firstChild) {
|
||||
element.removeChild(element.lastChild);
|
||||
}
|
||||
while (element.lastChild && element.lastChild !== element.firstChild) {
|
||||
element.removeChild(element.lastChild);
|
||||
}
|
||||
|
||||
let firstChild = element.firstChild;
|
||||
let firstChild = element.firstChild;
|
||||
|
||||
if (!firstChild) {
|
||||
element.appendChild(firstChild = textNode(''));
|
||||
}
|
||||
if (!firstChild) {
|
||||
element.appendChild(firstChild = textNode(''));
|
||||
}
|
||||
|
||||
if (hasEmojis(text)) {
|
||||
firstChild.nodeValue = '';
|
||||
appendAllNodes(element, createHtmlNodes(text, 2));
|
||||
} else {
|
||||
firstChild.nodeValue = text;
|
||||
}
|
||||
if (hasEmojis(text)) {
|
||||
firstChild.nodeValue = '';
|
||||
appendAllNodes(element, createHtmlNodes(text, 2));
|
||||
} else {
|
||||
firstChild.nodeValue = text;
|
||||
}
|
||||
}
|
||||
|
||||
export function findParentElement(element: HTMLElement, selector: string) {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
let current = element.parentElement;
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
let current = element.parentElement;
|
||||
|
||||
while (current && elements.indexOf(current) === -1) {
|
||||
current = current.parentElement;
|
||||
}
|
||||
while (current && elements.indexOf(current) === -1) {
|
||||
current = current.parentElement;
|
||||
}
|
||||
|
||||
return current;
|
||||
return current;
|
||||
}
|
||||
|
||||
export function findFocusableElements(root: HTMLElement) {
|
||||
const elements = root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
||||
return Array.from(elements) as HTMLElement[];
|
||||
const elements = root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
||||
return Array.from(elements) as HTMLElement[];
|
||||
}
|
||||
|
||||
export function focusFirstElement(root: HTMLElement) {
|
||||
const elements = findFocusableElements(root);
|
||||
const elements = findFocusableElements(root);
|
||||
|
||||
if (elements.length) {
|
||||
elements[0].focus();
|
||||
return elements[0];
|
||||
}
|
||||
if (elements.length) {
|
||||
elements[0].focus();
|
||||
return elements[0];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function focusElement(root: HTMLElement, selector: string) {
|
||||
const target = root.querySelector(selector) as HTMLElement | null;
|
||||
const target = root.querySelector(selector) as HTMLElement | null;
|
||||
|
||||
if (target) {
|
||||
target.focus();
|
||||
}
|
||||
if (target) {
|
||||
target.focus();
|
||||
}
|
||||
}
|
||||
|
||||
export function focusElementAfterTimeout(root: HTMLElement, selector: string) {
|
||||
setTimeout(() => focusElement(root, selector), 10);
|
||||
setTimeout(() => focusElement(root, selector), 10);
|
||||
}
|
||||
|
||||
export function isParentOf(parent: Element, child: Element) {
|
||||
for (let current = child.parentElement; current; current = current.parentElement) {
|
||||
if (current === parent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (let current = child.parentElement; current; current = current.parentElement) {
|
||||
if (current === parent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function showTextInNewTab(text: string) {
|
||||
const wnd = window.open()!;
|
||||
const pre = wnd.document.createElement('pre');
|
||||
pre.innerText = text;
|
||||
wnd.document.body.appendChild(pre);
|
||||
const wnd = window.open()!;
|
||||
const pre = wnd.document.createElement('pre');
|
||||
pre.innerText = text;
|
||||
wnd.document.body.appendChild(pre);
|
||||
}
|
||||
|
||||
export function addStyle(style: string) {
|
||||
const styleElement = document.createElement('style');
|
||||
styleElement.appendChild(document.createTextNode(style));
|
||||
document.head.appendChild(styleElement);
|
||||
return styleElement;
|
||||
const styleElement = document.createElement('style');
|
||||
styleElement.appendChild(document.createTextNode(style));
|
||||
document.head.appendChild(styleElement);
|
||||
return styleElement;
|
||||
}
|
||||
|
||||
+184
-184
@@ -1,206 +1,206 @@
|
||||
import {
|
||||
faCrown,
|
||||
faPlug,
|
||||
faGamepad,
|
||||
faMobile,
|
||||
faTablet,
|
||||
faTv,
|
||||
faCrown,
|
||||
faPlug,
|
||||
faGamepad,
|
||||
faMobile,
|
||||
faTablet,
|
||||
faTv,
|
||||
} from '../generated/fa-icons';
|
||||
|
||||
export {
|
||||
faHashtag,
|
||||
faCog,
|
||||
faCogs,
|
||||
faMinus,
|
||||
faPlus,
|
||||
faCheck,
|
||||
faFlag,
|
||||
faStickyNote,
|
||||
faCertificate,
|
||||
faGlobe,
|
||||
faGamepad,
|
||||
faDesktop,
|
||||
faQuestionCircle,
|
||||
faInfo,
|
||||
faSync,
|
||||
faUserSecret,
|
||||
faTrash,
|
||||
faLock,
|
||||
faApple,
|
||||
faEdit,
|
||||
faImage,
|
||||
faLaughBeam,
|
||||
faLanguage,
|
||||
faCircle,
|
||||
faEyeSlash,
|
||||
faEnvelope,
|
||||
faFont,
|
||||
faCompressArrowsAlt,
|
||||
faIdBadge,
|
||||
faFilter,
|
||||
faEraser,
|
||||
faBell,
|
||||
faClock,
|
||||
faComment,
|
||||
faComments,
|
||||
faCommentSlash,
|
||||
faHdd,
|
||||
faMicrochip,
|
||||
faUser,
|
||||
faUsers,
|
||||
faUserFriends,
|
||||
faSpinner,
|
||||
faBan,
|
||||
faMicrophoneSlash,
|
||||
faFileAlt,
|
||||
faTimes,
|
||||
faSearch,
|
||||
faClipboard,
|
||||
faChevronUp,
|
||||
faChevronDown,
|
||||
faChevronLeft,
|
||||
faChevronRight,
|
||||
faStar,
|
||||
faAngleDoubleUp,
|
||||
faAngleDoubleDown,
|
||||
faAngleDoubleLeft,
|
||||
faAngleDoubleRight,
|
||||
faPlay,
|
||||
faRedo,
|
||||
faSave,
|
||||
faArrowLeft,
|
||||
faArrowRight,
|
||||
faArrowUp,
|
||||
faArrowDown,
|
||||
faEyeDropper,
|
||||
faPaintBrush,
|
||||
faEllipsisV,
|
||||
faExclamationCircle,
|
||||
faUserPlus,
|
||||
faUserMinus,
|
||||
faUserTimes,
|
||||
faSignOutAlt,
|
||||
faStepForward,
|
||||
faVolumeOff,
|
||||
faVolumeDown,
|
||||
faVolumeUp,
|
||||
faHome,
|
||||
faStop,
|
||||
faRetweet,
|
||||
faFile,
|
||||
faCopy,
|
||||
faShare,
|
||||
faCode,
|
||||
faTerminal,
|
||||
faClone,
|
||||
faPause,
|
||||
faCrosshairs,
|
||||
faFileImage,
|
||||
faHeart,
|
||||
faPlusCircle,
|
||||
faMinusCircle,
|
||||
faInfoCircle,
|
||||
faCaretUp,
|
||||
faCaretSquareUp,
|
||||
faCaretSquareDown,
|
||||
faCheckCircle,
|
||||
faWrench,
|
||||
faDrawPolygon,
|
||||
faUserCog,
|
||||
faSlidersH,
|
||||
faExchangeAlt,
|
||||
faDatabase,
|
||||
faHorseHead,
|
||||
faMapMarkerAlt,
|
||||
faChartPie,
|
||||
faCalendar,
|
||||
faHashtag,
|
||||
faCog,
|
||||
faCogs,
|
||||
faMinus,
|
||||
faPlus,
|
||||
faCheck,
|
||||
faFlag,
|
||||
faStickyNote,
|
||||
faCertificate,
|
||||
faGlobe,
|
||||
faGamepad,
|
||||
faDesktop,
|
||||
faQuestionCircle,
|
||||
faInfo,
|
||||
faSync,
|
||||
faUserSecret,
|
||||
faTrash,
|
||||
faLock,
|
||||
faApple,
|
||||
faEdit,
|
||||
faImage,
|
||||
faLaughBeam,
|
||||
faLanguage,
|
||||
faCircle,
|
||||
faEyeSlash,
|
||||
faEnvelope,
|
||||
faFont,
|
||||
faCompressArrowsAlt,
|
||||
faIdBadge,
|
||||
faFilter,
|
||||
faEraser,
|
||||
faBell,
|
||||
faClock,
|
||||
faComment,
|
||||
faComments,
|
||||
faCommentSlash,
|
||||
faHdd,
|
||||
faMicrochip,
|
||||
faUser,
|
||||
faUsers,
|
||||
faUserFriends,
|
||||
faSpinner,
|
||||
faBan,
|
||||
faMicrophoneSlash,
|
||||
faFileAlt,
|
||||
faTimes,
|
||||
faSearch,
|
||||
faClipboard,
|
||||
faChevronUp,
|
||||
faChevronDown,
|
||||
faChevronLeft,
|
||||
faChevronRight,
|
||||
faStar,
|
||||
faAngleDoubleUp,
|
||||
faAngleDoubleDown,
|
||||
faAngleDoubleLeft,
|
||||
faAngleDoubleRight,
|
||||
faPlay,
|
||||
faRedo,
|
||||
faSave,
|
||||
faArrowLeft,
|
||||
faArrowRight,
|
||||
faArrowUp,
|
||||
faArrowDown,
|
||||
faEyeDropper,
|
||||
faPaintBrush,
|
||||
faEllipsisV,
|
||||
faExclamationCircle,
|
||||
faUserPlus,
|
||||
faUserMinus,
|
||||
faUserTimes,
|
||||
faSignOutAlt,
|
||||
faStepForward,
|
||||
faVolumeOff,
|
||||
faVolumeDown,
|
||||
faVolumeUp,
|
||||
faHome,
|
||||
faStop,
|
||||
faRetweet,
|
||||
faFile,
|
||||
faCopy,
|
||||
faShare,
|
||||
faCode,
|
||||
faTerminal,
|
||||
faClone,
|
||||
faPause,
|
||||
faCrosshairs,
|
||||
faFileImage,
|
||||
faHeart,
|
||||
faPlusCircle,
|
||||
faMinusCircle,
|
||||
faInfoCircle,
|
||||
faCaretUp,
|
||||
faCaretSquareUp,
|
||||
faCaretSquareDown,
|
||||
faCheckCircle,
|
||||
faWrench,
|
||||
faDrawPolygon,
|
||||
faUserCog,
|
||||
faSlidersH,
|
||||
faExchangeAlt,
|
||||
faDatabase,
|
||||
faHorseHead,
|
||||
faMapMarkerAlt,
|
||||
faChartPie,
|
||||
faCalendar,
|
||||
} from '../generated/fa-icons';
|
||||
|
||||
import {
|
||||
faPatreon,
|
||||
faDeviantart,
|
||||
faTwitter,
|
||||
faTumblr,
|
||||
faFacebook,
|
||||
faGithub,
|
||||
faVk,
|
||||
faGoogle,
|
||||
faChrome,
|
||||
faInternetExplorer,
|
||||
faEdge,
|
||||
faAndroid,
|
||||
faFirefox,
|
||||
faSafari,
|
||||
faOpera,
|
||||
faWindows,
|
||||
faApple,
|
||||
faLinux,
|
||||
faAmilia,
|
||||
faYandexInternational,
|
||||
faPatreon,
|
||||
faDeviantart,
|
||||
faTwitter,
|
||||
faTumblr,
|
||||
faFacebook,
|
||||
faGithub,
|
||||
faVk,
|
||||
faGoogle,
|
||||
faChrome,
|
||||
faInternetExplorer,
|
||||
faEdge,
|
||||
faAndroid,
|
||||
faFirefox,
|
||||
faSafari,
|
||||
faOpera,
|
||||
faWindows,
|
||||
faApple,
|
||||
faLinux,
|
||||
faAmilia,
|
||||
faYandexInternational,
|
||||
} from '../generated/fa-icons';
|
||||
|
||||
export {
|
||||
faPatreon,
|
||||
faDeviantart,
|
||||
faTwitter,
|
||||
faTumblr,
|
||||
faGithub,
|
||||
faPatreon,
|
||||
faDeviantart,
|
||||
faTwitter,
|
||||
faTumblr,
|
||||
faGithub,
|
||||
} from '../generated/fa-icons';
|
||||
|
||||
export const partyLeaderIcon = faCrown;
|
||||
export const offlineIcon = faPlug;
|
||||
export const emptyIcon = {
|
||||
prefix: 'fas',
|
||||
iconName: 'empty-icon',
|
||||
icon: [512, 512, [], 'ffff', ''],
|
||||
prefix: 'fas',
|
||||
iconName: 'empty-icon',
|
||||
icon: [512, 512, [], 'ffff', ''],
|
||||
};
|
||||
|
||||
export const oauthIcons: { [key: string]: any; } = {
|
||||
patreon: faPatreon,
|
||||
deviantart: faDeviantart,
|
||||
twitter: faTwitter,
|
||||
tumblr: faTumblr,
|
||||
facebook: faFacebook,
|
||||
github: faGithub,
|
||||
vkontakte: faVk,
|
||||
google: faGoogle,
|
||||
patreon: faPatreon,
|
||||
deviantart: faDeviantart,
|
||||
twitter: faTwitter,
|
||||
tumblr: faTumblr,
|
||||
facebook: faFacebook,
|
||||
github: faGithub,
|
||||
vkontakte: faVk,
|
||||
google: faGoogle,
|
||||
};
|
||||
|
||||
export const uaIcons: { [key: string]: any; } = {
|
||||
// browser
|
||||
'Chrome': faChrome,
|
||||
'Chromium': faChrome,
|
||||
'IE': faInternetExplorer,
|
||||
'Edge': faEdge,
|
||||
'Android Browser': faAndroid,
|
||||
'Firefox': faFirefox,
|
||||
'Safari': faSafari,
|
||||
'Mobile Safari': faSafari,
|
||||
'Opera': faOpera,
|
||||
'Opera Mini': faOpera,
|
||||
'Amigo': faAmilia,
|
||||
'YaBrowser': faYandexInternational,
|
||||
// os
|
||||
'Windows': faWindows,
|
||||
'Windows Phone': faWindows,
|
||||
'Android': faAndroid,
|
||||
'iOS': faApple,
|
||||
'Mac OS': faApple,
|
||||
'Arch': faLinux,
|
||||
'CentOS': faLinux,
|
||||
'Fedora': faLinux,
|
||||
'FreeBSD': faLinux,
|
||||
'OpenBSD': faLinux,
|
||||
'Debian': faLinux,
|
||||
'Ubuntu': faLinux,
|
||||
'Linux': faLinux,
|
||||
'Chromium OS': faChrome,
|
||||
'Firefox OS': faFirefox,
|
||||
'Playstation': faGamepad,
|
||||
'Nintendo': faGamepad,
|
||||
// device
|
||||
'console': faGamepad,
|
||||
'mobile': faMobile,
|
||||
'tablet': faTablet,
|
||||
'smarttv': faTv,
|
||||
// browser
|
||||
'Chrome': faChrome,
|
||||
'Chromium': faChrome,
|
||||
'IE': faInternetExplorer,
|
||||
'Edge': faEdge,
|
||||
'Android Browser': faAndroid,
|
||||
'Firefox': faFirefox,
|
||||
'Safari': faSafari,
|
||||
'Mobile Safari': faSafari,
|
||||
'Opera': faOpera,
|
||||
'Opera Mini': faOpera,
|
||||
'Amigo': faAmilia,
|
||||
'YaBrowser': faYandexInternational,
|
||||
// os
|
||||
'Windows': faWindows,
|
||||
'Windows Phone': faWindows,
|
||||
'Android': faAndroid,
|
||||
'iOS': faApple,
|
||||
'Mac OS': faApple,
|
||||
'Arch': faLinux,
|
||||
'CentOS': faLinux,
|
||||
'Fedora': faLinux,
|
||||
'FreeBSD': faLinux,
|
||||
'OpenBSD': faLinux,
|
||||
'Debian': faLinux,
|
||||
'Ubuntu': faLinux,
|
||||
'Linux': faLinux,
|
||||
'Chromium OS': faChrome,
|
||||
'Firefox OS': faFirefox,
|
||||
'Playstation': faGamepad,
|
||||
'Nintendo': faGamepad,
|
||||
// device
|
||||
'console': faGamepad,
|
||||
'mobile': faMobile,
|
||||
'tablet': faTablet,
|
||||
'smarttv': faTv,
|
||||
};
|
||||
|
||||
+113
-113
@@ -4,157 +4,157 @@ import { InputManager } from './inputManager';
|
||||
import { isFocused } from '../clientUtils';
|
||||
|
||||
interface GamepadInstance {
|
||||
gamepad: Gamepad;
|
||||
mapping: GamepadMapping;
|
||||
gamepad: Gamepad;
|
||||
mapping: GamepadMapping;
|
||||
}
|
||||
|
||||
const JOYSTICK_THRESHHOLD = 0.2;
|
||||
|
||||
function createGamepad(gamepad: Gamepad): GamepadInstance {
|
||||
const mapping = detectMapping(gamepad.id, navigator.userAgent);
|
||||
return { gamepad, mapping };
|
||||
const mapping = detectMapping(gamepad.id, navigator.userAgent);
|
||||
return { gamepad, mapping };
|
||||
}
|
||||
|
||||
function isCompatible(mapping: any, id: string, browser: string) {
|
||||
for (let i = 0; i < mapping.supported.length; i++) {
|
||||
const supported = mapping.supported[i];
|
||||
for (let i = 0; i < mapping.supported.length; i++) {
|
||||
const supported = mapping.supported[i];
|
||||
|
||||
if (id.indexOf(supported.id) !== -1 && browser.indexOf(supported.os) !== -1 && browser.indexOf(browser) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (id.indexOf(supported.id) !== -1 && browser.indexOf(supported.os) !== -1 && browser.indexOf(browser) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
function detectMapping(id: string, browser: string) {
|
||||
for (let i = 0; i < GAMEPAD_MAPPINGS.length; i++) {
|
||||
if (isCompatible(GAMEPAD_MAPPINGS[i], id, browser)) {
|
||||
return GAMEPAD_MAPPINGS[i];
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < GAMEPAD_MAPPINGS.length; i++) {
|
||||
if (isCompatible(GAMEPAD_MAPPINGS[i], id, browser)) {
|
||||
return GAMEPAD_MAPPINGS[i];
|
||||
}
|
||||
}
|
||||
|
||||
return GAMEPAD_MAPPINGS[0];
|
||||
return GAMEPAD_MAPPINGS[0];
|
||||
}
|
||||
|
||||
function axis({ mapping, gamepad }: GamepadInstance, name: GamepadAxes) {
|
||||
const axe = mapping.axes[name] as any;
|
||||
return axe ? gamepad.axes[axe.index] : 0;
|
||||
const axe = mapping.axes[name] as any;
|
||||
return axe ? gamepad.axes[axe.index] : 0;
|
||||
}
|
||||
function button({ mapping, gamepad }: GamepadInstance, name: GamepadButtons) {
|
||||
const button = mapping.buttons[name] as any;
|
||||
const button = mapping.buttons[name] as any;
|
||||
|
||||
if (!button) {
|
||||
return false;
|
||||
}
|
||||
if (!button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (button.index !== undefined) {
|
||||
return gamepad.buttons[button.index] && gamepad.buttons[button.index].pressed;
|
||||
}
|
||||
if (button.index !== undefined) {
|
||||
return gamepad.buttons[button.index] && gamepad.buttons[button.index].pressed;
|
||||
}
|
||||
|
||||
if (button.axis !== undefined) {
|
||||
if (button.direction < 0) {
|
||||
return gamepad.axes[button.axis] < -0.75;
|
||||
} else {
|
||||
return gamepad.axes[button.axis] > 0.75;
|
||||
}
|
||||
}
|
||||
if (button.axis !== undefined) {
|
||||
if (button.direction < 0) {
|
||||
return gamepad.axes[button.axis] < -0.75;
|
||||
} else {
|
||||
return gamepad.axes[button.axis] > 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
export class GamePadController implements InputController {
|
||||
private initialized = false;
|
||||
private gamepadIndex = -1;
|
||||
private zeroed1 = false;
|
||||
private zeroed2 = false;
|
||||
constructor(private manager: InputManager) {
|
||||
}
|
||||
initialize() {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
window.addEventListener('gamepadconnected', this.gamepadconnected);
|
||||
window.addEventListener('gamepaddisconnected', this.gamepaddisconnected);
|
||||
this.scanGamepads();
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.initialized = false;
|
||||
window.removeEventListener('gamepadconnected', this.gamepadconnected);
|
||||
window.removeEventListener('gamepaddisconnected', this.gamepaddisconnected);
|
||||
}
|
||||
update() {
|
||||
if (this.manager.disabledGamepad || !isFocused() || this.gamepadIndex === -1)
|
||||
return;
|
||||
private initialized = false;
|
||||
private gamepadIndex = -1;
|
||||
private zeroed1 = false;
|
||||
private zeroed2 = false;
|
||||
constructor(private manager: InputManager) {
|
||||
}
|
||||
initialize() {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
window.addEventListener('gamepadconnected', this.gamepadconnected);
|
||||
window.addEventListener('gamepaddisconnected', this.gamepaddisconnected);
|
||||
this.scanGamepads();
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.initialized = false;
|
||||
window.removeEventListener('gamepadconnected', this.gamepadconnected);
|
||||
window.removeEventListener('gamepaddisconnected', this.gamepaddisconnected);
|
||||
}
|
||||
update() {
|
||||
if (this.manager.disabledGamepad || !isFocused() || this.gamepadIndex === -1)
|
||||
return;
|
||||
|
||||
const gamepads = navigator.getGamepads();
|
||||
const gamepad = gamepads[this.gamepadIndex];
|
||||
const gamepads = navigator.getGamepads();
|
||||
const gamepad = gamepads[this.gamepadIndex];
|
||||
|
||||
if (!gamepad) {
|
||||
this.scanGamepads();
|
||||
return;
|
||||
}
|
||||
if (!gamepad) {
|
||||
this.scanGamepads();
|
||||
return;
|
||||
}
|
||||
|
||||
const pad = createGamepad(gamepad);
|
||||
const pad = createGamepad(gamepad);
|
||||
|
||||
this.zeroed1 = readAxis(
|
||||
this.manager, Key.GAMEPAD_AXIS1_X, Key.GAMEPAD_AXIS1_Y,
|
||||
axis(pad, GamepadAxes.LeftStickX), axis(pad, GamepadAxes.LeftStickY), this.zeroed1);
|
||||
this.zeroed2 = readAxis(
|
||||
this.manager, Key.GAMEPAD_AXIS2_X, Key.GAMEPAD_AXIS2_Y,
|
||||
axis(pad, GamepadAxes.RightStickX), axis(pad, GamepadAxes.RightStickY), this.zeroed2);
|
||||
this.zeroed1 = readAxis(
|
||||
this.manager, Key.GAMEPAD_AXIS1_X, Key.GAMEPAD_AXIS1_Y,
|
||||
axis(pad, GamepadAxes.LeftStickX), axis(pad, GamepadAxes.LeftStickY), this.zeroed1);
|
||||
this.zeroed2 = readAxis(
|
||||
this.manager, Key.GAMEPAD_AXIS2_X, Key.GAMEPAD_AXIS2_Y,
|
||||
axis(pad, GamepadAxes.RightStickX), axis(pad, GamepadAxes.RightStickY), this.zeroed2);
|
||||
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_X, button(pad, GamepadButtons.X) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_Y, button(pad, GamepadButtons.Y) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_A, button(pad, GamepadButtons.A) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_B, button(pad, GamepadButtons.B) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_X, button(pad, GamepadButtons.X) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_Y, button(pad, GamepadButtons.Y) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_A, button(pad, GamepadButtons.A) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_B, button(pad, GamepadButtons.B) ? 1 : 0);
|
||||
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_DOWN, button(pad, GamepadButtons.DpadDown) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_LEFT, button(pad, GamepadButtons.DpadLeft) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_RIGHT, button(pad, GamepadButtons.DpadRight) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_UP, button(pad, GamepadButtons.DpadUp) ? 1 : 0);
|
||||
}
|
||||
clear() {
|
||||
}
|
||||
private scanGamepads() {
|
||||
const gamepads = navigator.getGamepads();
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_DOWN, button(pad, GamepadButtons.DpadDown) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_LEFT, button(pad, GamepadButtons.DpadLeft) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_RIGHT, button(pad, GamepadButtons.DpadRight) ? 1 : 0);
|
||||
this.manager.setValue(Key.GAMEPAD_BUTTON_UP, button(pad, GamepadButtons.DpadUp) ? 1 : 0);
|
||||
}
|
||||
clear() {
|
||||
}
|
||||
private scanGamepads() {
|
||||
const gamepads = navigator.getGamepads();
|
||||
|
||||
// Using regular loop because of issues with iterating over gamepads
|
||||
for (let i = 0; i < gamepads.length; i++) {
|
||||
const gamepad = gamepads[i];
|
||||
// Using regular loop because of issues with iterating over gamepads
|
||||
for (let i = 0; i < gamepads.length; i++) {
|
||||
const gamepad = gamepads[i];
|
||||
|
||||
if (gamepad) {
|
||||
this.gamepadIndex = gamepad.index;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (gamepad) {
|
||||
this.gamepadIndex = gamepad.index;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.gamepadIndex = -1;
|
||||
}
|
||||
private gamepadconnected = (e: Event) => {
|
||||
this.gamepadIndex = (e as GamepadEvent).gamepad.index;
|
||||
}
|
||||
private gamepaddisconnected = (e: Event) => {
|
||||
if (this.gamepadIndex === (e as GamepadEvent).gamepad.index) {
|
||||
this.scanGamepads();
|
||||
}
|
||||
}
|
||||
this.gamepadIndex = -1;
|
||||
}
|
||||
private gamepadconnected = (e: Event) => {
|
||||
this.gamepadIndex = (e as GamepadEvent).gamepad.index;
|
||||
}
|
||||
private gamepaddisconnected = (e: Event) => {
|
||||
if (this.gamepadIndex === (e as GamepadEvent).gamepad.index) {
|
||||
this.scanGamepads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readAxis(manager: InputManager, keyX: Key, keyY: Key, axisX: number, axisY: number, zeroed: boolean): boolean {
|
||||
const dist = Math.sqrt(axisX * axisX + axisY * axisY);
|
||||
const dist = Math.sqrt(axisX * axisX + axisY * axisY);
|
||||
|
||||
if (dist > JOYSTICK_THRESHHOLD) {
|
||||
const scaledDist = Math.min((dist - JOYSTICK_THRESHHOLD) / (1 - JOYSTICK_THRESHHOLD), 1);
|
||||
const theta = Math.atan2(axisY, axisX);
|
||||
manager.setValue(keyX, Math.cos(theta) * scaledDist);
|
||||
manager.setValue(keyY, Math.sin(theta) * scaledDist);
|
||||
return false;
|
||||
} else if (!zeroed) {
|
||||
manager.setValue(keyX, 0);
|
||||
manager.setValue(keyY, 0);
|
||||
return true;
|
||||
}
|
||||
if (dist > JOYSTICK_THRESHHOLD) {
|
||||
const scaledDist = Math.min((dist - JOYSTICK_THRESHHOLD) / (1 - JOYSTICK_THRESHHOLD), 1);
|
||||
const theta = Math.atan2(axisY, axisX);
|
||||
manager.setValue(keyX, Math.cos(theta) * scaledDist);
|
||||
manager.setValue(keyY, Math.sin(theta) * scaledDist);
|
||||
return false;
|
||||
} else if (!zeroed) {
|
||||
manager.setValue(keyX, 0);
|
||||
manager.setValue(keyY, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return zeroed;
|
||||
return zeroed;
|
||||
}
|
||||
|
||||
+139
-139
@@ -1,144 +1,144 @@
|
||||
export const enum Key {
|
||||
// Keyboard
|
||||
BACKSPACE = 8,
|
||||
TAB = 9,
|
||||
ENTER = 13,
|
||||
SHIFT = 16,
|
||||
CTRL = 17,
|
||||
ALT = 18,
|
||||
PAUSE = 19,
|
||||
CAPS_LOCK = 20,
|
||||
ESCAPE = 27,
|
||||
SPACE = 32,
|
||||
PAGE_UP = 33,
|
||||
PAGE_DOWN = 34,
|
||||
END = 35,
|
||||
HOME = 36,
|
||||
LEFT = 37,
|
||||
UP = 38,
|
||||
RIGHT = 39,
|
||||
DOWN = 40,
|
||||
INSERT = 45,
|
||||
DELETE = 46,
|
||||
KEY_0 = 48,
|
||||
KEY_1 = 49,
|
||||
KEY_2 = 50,
|
||||
KEY_3 = 51,
|
||||
KEY_4 = 52,
|
||||
KEY_5 = 53,
|
||||
KEY_6 = 54,
|
||||
KEY_7 = 55,
|
||||
KEY_8 = 56,
|
||||
KEY_9 = 57,
|
||||
KEY_A = 65,
|
||||
KEY_B = 66,
|
||||
KEY_C = 67,
|
||||
KEY_D = 68,
|
||||
KEY_E = 69,
|
||||
KEY_F = 70,
|
||||
KEY_G = 71,
|
||||
KEY_H = 72,
|
||||
KEY_I = 73,
|
||||
KEY_J = 74,
|
||||
KEY_K = 75,
|
||||
KEY_L = 76,
|
||||
KEY_M = 77,
|
||||
KEY_N = 78,
|
||||
KEY_O = 79,
|
||||
KEY_P = 80,
|
||||
KEY_Q = 81,
|
||||
KEY_R = 82,
|
||||
KEY_S = 83,
|
||||
KEY_T = 84,
|
||||
KEY_U = 85,
|
||||
KEY_V = 86,
|
||||
KEY_W = 87,
|
||||
KEY_X = 88,
|
||||
KEY_Y = 89,
|
||||
KEY_Z = 90,
|
||||
LEFT_META = 91,
|
||||
RIGHT_META = 92,
|
||||
SELECT = 93,
|
||||
NUMPAD_0 = 96,
|
||||
NUMPAD_1 = 97,
|
||||
NUMPAD_2 = 98,
|
||||
NUMPAD_3 = 99,
|
||||
NUMPAD_4 = 100,
|
||||
NUMPAD_5 = 101,
|
||||
NUMPAD_6 = 102,
|
||||
NUMPAD_7 = 103,
|
||||
NUMPAD_8 = 104,
|
||||
NUMPAD_9 = 105,
|
||||
MULTIPLY = 106,
|
||||
ADD = 107,
|
||||
SUBTRACT = 109,
|
||||
DECIMAL = 110,
|
||||
DIVIDE = 111,
|
||||
F1 = 112,
|
||||
F2 = 113,
|
||||
F3 = 114,
|
||||
F4 = 115,
|
||||
F5 = 116,
|
||||
F6 = 117,
|
||||
F7 = 118,
|
||||
F8 = 119,
|
||||
F9 = 120,
|
||||
F10 = 121,
|
||||
F11 = 122,
|
||||
F12 = 123,
|
||||
NUM_LOCK = 144,
|
||||
SCROLL_LOCK = 145,
|
||||
SEMICOLON = 186,
|
||||
EQUALS = 187,
|
||||
COMMA = 188,
|
||||
DASH = 189,
|
||||
PERIOD = 190,
|
||||
FORWARD_SLASH = 191,
|
||||
GRAVE_ACCENT = 192,
|
||||
OPEN_BRACKET = 219,
|
||||
BACK_SLASH = 220,
|
||||
CLOSE_BRACKET = 221,
|
||||
SINGLE_QUOTE = 222,
|
||||
// Mouse
|
||||
MOUSE_X = 300,
|
||||
MOUSE_Y,
|
||||
MOUSE_BUTTON1,
|
||||
MOUSE_BUTTON2,
|
||||
MOUSE_BUTTON3,
|
||||
MOUSE_WHEEL_X,
|
||||
MOUSE_WHEEL_Y,
|
||||
// Gamepad
|
||||
GAMEPAD_AXIS1_X,
|
||||
GAMEPAD_AXIS1_Y,
|
||||
GAMEPAD_AXIS2_X,
|
||||
GAMEPAD_AXIS2_Y,
|
||||
GAMEPAD_BUTTON_A,
|
||||
GAMEPAD_BUTTON_B,
|
||||
GAMEPAD_BUTTON_X,
|
||||
GAMEPAD_BUTTON_Y,
|
||||
GAMEPAD_BUTTON_L1,
|
||||
GAMEPAD_BUTTON_R1,
|
||||
GAMEPAD_BUTTON_L2,
|
||||
GAMEPAD_BUTTON_R2,
|
||||
GAMEPAD_BUTTON_START,
|
||||
GAMEPAD_BUTTON_SELECT,
|
||||
GAMEPAD_BUTTON_ANALOG1,
|
||||
GAMEPAD_BUTTON_ANALOG2,
|
||||
GAMEPAD_BUTTON_UP,
|
||||
GAMEPAD_BUTTON_DOWN,
|
||||
GAMEPAD_BUTTON_LEFT,
|
||||
GAMEPAD_BUTTON_RIGHT,
|
||||
// Touch
|
||||
TOUCH,
|
||||
TOUCH_CLICK,
|
||||
TOUCH_SECOND_CLICK,
|
||||
// Other
|
||||
MAX_VALUE,
|
||||
// Keyboard
|
||||
BACKSPACE = 8,
|
||||
TAB = 9,
|
||||
ENTER = 13,
|
||||
SHIFT = 16,
|
||||
CTRL = 17,
|
||||
ALT = 18,
|
||||
PAUSE = 19,
|
||||
CAPS_LOCK = 20,
|
||||
ESCAPE = 27,
|
||||
SPACE = 32,
|
||||
PAGE_UP = 33,
|
||||
PAGE_DOWN = 34,
|
||||
END = 35,
|
||||
HOME = 36,
|
||||
LEFT = 37,
|
||||
UP = 38,
|
||||
RIGHT = 39,
|
||||
DOWN = 40,
|
||||
INSERT = 45,
|
||||
DELETE = 46,
|
||||
KEY_0 = 48,
|
||||
KEY_1 = 49,
|
||||
KEY_2 = 50,
|
||||
KEY_3 = 51,
|
||||
KEY_4 = 52,
|
||||
KEY_5 = 53,
|
||||
KEY_6 = 54,
|
||||
KEY_7 = 55,
|
||||
KEY_8 = 56,
|
||||
KEY_9 = 57,
|
||||
KEY_A = 65,
|
||||
KEY_B = 66,
|
||||
KEY_C = 67,
|
||||
KEY_D = 68,
|
||||
KEY_E = 69,
|
||||
KEY_F = 70,
|
||||
KEY_G = 71,
|
||||
KEY_H = 72,
|
||||
KEY_I = 73,
|
||||
KEY_J = 74,
|
||||
KEY_K = 75,
|
||||
KEY_L = 76,
|
||||
KEY_M = 77,
|
||||
KEY_N = 78,
|
||||
KEY_O = 79,
|
||||
KEY_P = 80,
|
||||
KEY_Q = 81,
|
||||
KEY_R = 82,
|
||||
KEY_S = 83,
|
||||
KEY_T = 84,
|
||||
KEY_U = 85,
|
||||
KEY_V = 86,
|
||||
KEY_W = 87,
|
||||
KEY_X = 88,
|
||||
KEY_Y = 89,
|
||||
KEY_Z = 90,
|
||||
LEFT_META = 91,
|
||||
RIGHT_META = 92,
|
||||
SELECT = 93,
|
||||
NUMPAD_0 = 96,
|
||||
NUMPAD_1 = 97,
|
||||
NUMPAD_2 = 98,
|
||||
NUMPAD_3 = 99,
|
||||
NUMPAD_4 = 100,
|
||||
NUMPAD_5 = 101,
|
||||
NUMPAD_6 = 102,
|
||||
NUMPAD_7 = 103,
|
||||
NUMPAD_8 = 104,
|
||||
NUMPAD_9 = 105,
|
||||
MULTIPLY = 106,
|
||||
ADD = 107,
|
||||
SUBTRACT = 109,
|
||||
DECIMAL = 110,
|
||||
DIVIDE = 111,
|
||||
F1 = 112,
|
||||
F2 = 113,
|
||||
F3 = 114,
|
||||
F4 = 115,
|
||||
F5 = 116,
|
||||
F6 = 117,
|
||||
F7 = 118,
|
||||
F8 = 119,
|
||||
F9 = 120,
|
||||
F10 = 121,
|
||||
F11 = 122,
|
||||
F12 = 123,
|
||||
NUM_LOCK = 144,
|
||||
SCROLL_LOCK = 145,
|
||||
SEMICOLON = 186,
|
||||
EQUALS = 187,
|
||||
COMMA = 188,
|
||||
DASH = 189,
|
||||
PERIOD = 190,
|
||||
FORWARD_SLASH = 191,
|
||||
GRAVE_ACCENT = 192,
|
||||
OPEN_BRACKET = 219,
|
||||
BACK_SLASH = 220,
|
||||
CLOSE_BRACKET = 221,
|
||||
SINGLE_QUOTE = 222,
|
||||
// Mouse
|
||||
MOUSE_X = 300,
|
||||
MOUSE_Y,
|
||||
MOUSE_BUTTON1,
|
||||
MOUSE_BUTTON2,
|
||||
MOUSE_BUTTON3,
|
||||
MOUSE_WHEEL_X,
|
||||
MOUSE_WHEEL_Y,
|
||||
// Gamepad
|
||||
GAMEPAD_AXIS1_X,
|
||||
GAMEPAD_AXIS1_Y,
|
||||
GAMEPAD_AXIS2_X,
|
||||
GAMEPAD_AXIS2_Y,
|
||||
GAMEPAD_BUTTON_A,
|
||||
GAMEPAD_BUTTON_B,
|
||||
GAMEPAD_BUTTON_X,
|
||||
GAMEPAD_BUTTON_Y,
|
||||
GAMEPAD_BUTTON_L1,
|
||||
GAMEPAD_BUTTON_R1,
|
||||
GAMEPAD_BUTTON_L2,
|
||||
GAMEPAD_BUTTON_R2,
|
||||
GAMEPAD_BUTTON_START,
|
||||
GAMEPAD_BUTTON_SELECT,
|
||||
GAMEPAD_BUTTON_ANALOG1,
|
||||
GAMEPAD_BUTTON_ANALOG2,
|
||||
GAMEPAD_BUTTON_UP,
|
||||
GAMEPAD_BUTTON_DOWN,
|
||||
GAMEPAD_BUTTON_LEFT,
|
||||
GAMEPAD_BUTTON_RIGHT,
|
||||
// Touch
|
||||
TOUCH,
|
||||
TOUCH_CLICK,
|
||||
TOUCH_SECOND_CLICK,
|
||||
// Other
|
||||
MAX_VALUE,
|
||||
}
|
||||
|
||||
export interface InputController {
|
||||
initialize(element: HTMLElement): void;
|
||||
release(): void;
|
||||
update(): void;
|
||||
clear(): void;
|
||||
initialize(element: HTMLElement): void;
|
||||
release(): void;
|
||||
update(): void;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
+148
-148
@@ -11,160 +11,160 @@ type Handler = (input: Key, value: number) => boolean | void;
|
||||
const KEYS = Key.MAX_VALUE;
|
||||
|
||||
export class InputManager {
|
||||
disabledGamepad = false;
|
||||
disabledKeyboard = false;
|
||||
disableArrows = false;
|
||||
usingTouch = false;
|
||||
private state: number[];
|
||||
private prevState: number[];
|
||||
private actions: Handler[][];
|
||||
private controllers: InputController[] = [];
|
||||
constructor() {
|
||||
this.state = array(KEYS, 0);
|
||||
this.prevState = array(KEYS, 0);
|
||||
this.actions = times(KEYS, () => []);
|
||||
}
|
||||
get axisX() {
|
||||
const axisX = this.getRange(Key.GAMEPAD_AXIS1_X);
|
||||
const left = this.disableArrows ? this.getState(Key.KEY_A) : this.getState(Key.LEFT, Key.KEY_A);
|
||||
const right = this.disableArrows ? this.getState(Key.KEY_D) : this.getState(Key.RIGHT, Key.KEY_D);
|
||||
const x = axisX + (left ? -1 : (right ? 1 : 0));
|
||||
return clamp(x, -1, 1);
|
||||
}
|
||||
get axisY() {
|
||||
const axisY = this.getRange(Key.GAMEPAD_AXIS1_Y);
|
||||
const up = this.disableArrows ? this.getState(Key.KEY_W) : this.getState(Key.UP, Key.KEY_W);
|
||||
const down = this.disableArrows ? this.getState(Key.KEY_S) : this.getState(Key.DOWN, Key.KEY_S);
|
||||
const y = axisY + (up ? -1 : (down ? 1 : 0));
|
||||
return clamp(y, -1, 1);
|
||||
}
|
||||
get isMovementFromButtons() {
|
||||
const up = this.getState(Key.UP, Key.KEY_W);
|
||||
const down = this.getState(Key.DOWN, Key.KEY_S);
|
||||
const left = this.getState(Key.LEFT, Key.KEY_A);
|
||||
const right = this.getState(Key.RIGHT, Key.KEY_D);
|
||||
return up || down || left || right;
|
||||
}
|
||||
get axis2X() {
|
||||
return clamp(this.getRange(Key.GAMEPAD_AXIS2_X), -1, 1);
|
||||
}
|
||||
get axis2Y() {
|
||||
return clamp(this.getRange(Key.GAMEPAD_AXIS2_Y), -1, 1);
|
||||
}
|
||||
get pointerX() {
|
||||
return this.getRange(Key.MOUSE_X);
|
||||
}
|
||||
get pointerY() {
|
||||
return this.getRange(Key.MOUSE_Y);
|
||||
}
|
||||
get wheelX() {
|
||||
return this.getRange(Key.MOUSE_WHEEL_X);
|
||||
}
|
||||
get wheelY() {
|
||||
return this.getRange(Key.MOUSE_WHEEL_Y);
|
||||
}
|
||||
initialize(element: HTMLElement) {
|
||||
this.controllers = [
|
||||
new KeyboardController(this),
|
||||
new MouseController(this),
|
||||
new TouchController(this),
|
||||
new GamePadController(this),
|
||||
];
|
||||
disabledGamepad = false;
|
||||
disabledKeyboard = false;
|
||||
disableArrows = false;
|
||||
usingTouch = false;
|
||||
private state: number[];
|
||||
private prevState: number[];
|
||||
private actions: Handler[][];
|
||||
private controllers: InputController[] = [];
|
||||
constructor() {
|
||||
this.state = array(KEYS, 0);
|
||||
this.prevState = array(KEYS, 0);
|
||||
this.actions = times(KEYS, () => []);
|
||||
}
|
||||
get axisX() {
|
||||
const axisX = this.getRange(Key.GAMEPAD_AXIS1_X);
|
||||
const left = this.disableArrows ? this.getState(Key.KEY_A) : this.getState(Key.LEFT, Key.KEY_A);
|
||||
const right = this.disableArrows ? this.getState(Key.KEY_D) : this.getState(Key.RIGHT, Key.KEY_D);
|
||||
const x = axisX + (left ? -1 : (right ? 1 : 0));
|
||||
return clamp(x, -1, 1);
|
||||
}
|
||||
get axisY() {
|
||||
const axisY = this.getRange(Key.GAMEPAD_AXIS1_Y);
|
||||
const up = this.disableArrows ? this.getState(Key.KEY_W) : this.getState(Key.UP, Key.KEY_W);
|
||||
const down = this.disableArrows ? this.getState(Key.KEY_S) : this.getState(Key.DOWN, Key.KEY_S);
|
||||
const y = axisY + (up ? -1 : (down ? 1 : 0));
|
||||
return clamp(y, -1, 1);
|
||||
}
|
||||
get isMovementFromButtons() {
|
||||
const up = this.getState(Key.UP, Key.KEY_W);
|
||||
const down = this.getState(Key.DOWN, Key.KEY_S);
|
||||
const left = this.getState(Key.LEFT, Key.KEY_A);
|
||||
const right = this.getState(Key.RIGHT, Key.KEY_D);
|
||||
return up || down || left || right;
|
||||
}
|
||||
get axis2X() {
|
||||
return clamp(this.getRange(Key.GAMEPAD_AXIS2_X), -1, 1);
|
||||
}
|
||||
get axis2Y() {
|
||||
return clamp(this.getRange(Key.GAMEPAD_AXIS2_Y), -1, 1);
|
||||
}
|
||||
get pointerX() {
|
||||
return this.getRange(Key.MOUSE_X);
|
||||
}
|
||||
get pointerY() {
|
||||
return this.getRange(Key.MOUSE_Y);
|
||||
}
|
||||
get wheelX() {
|
||||
return this.getRange(Key.MOUSE_WHEEL_X);
|
||||
}
|
||||
get wheelY() {
|
||||
return this.getRange(Key.MOUSE_WHEEL_Y);
|
||||
}
|
||||
initialize(element: HTMLElement) {
|
||||
this.controllers = [
|
||||
new KeyboardController(this),
|
||||
new MouseController(this),
|
||||
new TouchController(this),
|
||||
new GamePadController(this),
|
||||
];
|
||||
|
||||
this.controllers.forEach(c => c.initialize(element));
|
||||
this.clear();
|
||||
}
|
||||
release() {
|
||||
this.controllers.forEach(c => c.release());
|
||||
this.controllers = [];
|
||||
this.clear();
|
||||
}
|
||||
update() {
|
||||
for (const controller of this.controllers) {
|
||||
controller.update();
|
||||
}
|
||||
}
|
||||
end() {
|
||||
for (let i = 0; i < KEYS; i++) {
|
||||
this.prevState[i] = this.state[i];
|
||||
}
|
||||
this.controllers.forEach(c => c.initialize(element));
|
||||
this.clear();
|
||||
}
|
||||
release() {
|
||||
this.controllers.forEach(c => c.release());
|
||||
this.controllers = [];
|
||||
this.clear();
|
||||
}
|
||||
update() {
|
||||
for (const controller of this.controllers) {
|
||||
controller.update();
|
||||
}
|
||||
}
|
||||
end() {
|
||||
for (let i = 0; i < KEYS; i++) {
|
||||
this.prevState[i] = this.state[i];
|
||||
}
|
||||
|
||||
this.setValue(Key.TOUCH_CLICK, 0);
|
||||
this.setValue(Key.TOUCH_SECOND_CLICK, 0);
|
||||
this.setValue(Key.MOUSE_WHEEL_X, 0);
|
||||
this.setValue(Key.MOUSE_WHEEL_Y, 0);
|
||||
}
|
||||
clear() {
|
||||
for (let i = 0; i < KEYS; i++) {
|
||||
this.state[i] = 0;
|
||||
this.prevState[i] = 0;
|
||||
}
|
||||
this.setValue(Key.TOUCH_CLICK, 0);
|
||||
this.setValue(Key.TOUCH_SECOND_CLICK, 0);
|
||||
this.setValue(Key.MOUSE_WHEEL_X, 0);
|
||||
this.setValue(Key.MOUSE_WHEEL_Y, 0);
|
||||
}
|
||||
clear() {
|
||||
for (let i = 0; i < KEYS; i++) {
|
||||
this.state[i] = 0;
|
||||
this.prevState[i] = 0;
|
||||
}
|
||||
|
||||
for (const controller of this.controllers) {
|
||||
controller.clear();
|
||||
}
|
||||
}
|
||||
onPressed(inputs: Key[] | Key, handler: () => void) {
|
||||
this.onAction(inputs, (_, v) => {
|
||||
if (v === 1) {
|
||||
handler();
|
||||
}
|
||||
});
|
||||
}
|
||||
onReleased(inputs: Key[] | Key, handler: () => void) {
|
||||
this.onAction(inputs, (_, v) => {
|
||||
if (v === 0) {
|
||||
handler();
|
||||
}
|
||||
});
|
||||
}
|
||||
isPressed(key: Key) {
|
||||
return this.state[key] !== 0;
|
||||
}
|
||||
wasPressed(key: Key): boolean {
|
||||
return this.state[key] === 1 && this.prevState[key] === 0;
|
||||
}
|
||||
private onAction(inputs: Key[] | Key, handler: Handler) {
|
||||
const inputsArray = Array.isArray(inputs) ? inputs : [inputs];
|
||||
for (const controller of this.controllers) {
|
||||
controller.clear();
|
||||
}
|
||||
}
|
||||
onPressed(inputs: Key[] | Key, handler: () => void) {
|
||||
this.onAction(inputs, (_, v) => {
|
||||
if (v === 1) {
|
||||
handler();
|
||||
}
|
||||
});
|
||||
}
|
||||
onReleased(inputs: Key[] | Key, handler: () => void) {
|
||||
this.onAction(inputs, (_, v) => {
|
||||
if (v === 0) {
|
||||
handler();
|
||||
}
|
||||
});
|
||||
}
|
||||
isPressed(key: Key) {
|
||||
return this.state[key] !== 0;
|
||||
}
|
||||
wasPressed(key: Key): boolean {
|
||||
return this.state[key] === 1 && this.prevState[key] === 0;
|
||||
}
|
||||
private onAction(inputs: Key[] | Key, handler: Handler) {
|
||||
const inputsArray = Array.isArray(inputs) ? inputs : [inputs];
|
||||
|
||||
for (const i of inputsArray) {
|
||||
this.actions[i].push(handler);
|
||||
}
|
||||
}
|
||||
private getState(...inputs: Key[]): boolean {
|
||||
for (const i of inputs) {
|
||||
if (this.state[i] !== 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const i of inputsArray) {
|
||||
this.actions[i].push(handler);
|
||||
}
|
||||
}
|
||||
private getState(...inputs: Key[]): boolean {
|
||||
for (const i of inputs) {
|
||||
if (this.state[i] !== 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private getRange(input: Key): number {
|
||||
return this.state[input];
|
||||
}
|
||||
setValue(input: Key, value: number): boolean {
|
||||
if (input < 0 || input >= KEYS) {
|
||||
console.warn(`Input out of range: ${input}`);
|
||||
} else if (this.state[input] !== value) {
|
||||
this.state[input] = value;
|
||||
return false;
|
||||
}
|
||||
private getRange(input: Key): number {
|
||||
return this.state[input];
|
||||
}
|
||||
setValue(input: Key, value: number): boolean {
|
||||
if (input < 0 || input >= KEYS) {
|
||||
console.warn(`Input out of range: ${input}`);
|
||||
} else if (this.state[input] !== value) {
|
||||
this.state[input] = value;
|
||||
|
||||
if (this.actions[input] && this.actions[input].length) {
|
||||
for (const action of this.actions[input]) {
|
||||
action(input, value);
|
||||
}
|
||||
if (this.actions[input] && this.actions[input].length) {
|
||||
for (const action of this.actions[input]) {
|
||||
action(input, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
addValue(input: Key, value: number) {
|
||||
if (input < 0 || input >= KEYS) {
|
||||
console.warn(`Input out of range: ${input}`);
|
||||
} else {
|
||||
this.state[input] += value;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
addValue(input: Key, value: number) {
|
||||
if (input < 0 || input >= KEYS) {
|
||||
console.warn(`Input out of range: ${input}`);
|
||||
} else {
|
||||
this.state[input] += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,92 +5,92 @@ import { removeItem, includes } from '../../common/utils';
|
||||
const firefox = !SERVER && /firefox/i.test(navigator.userAgent);
|
||||
|
||||
function isKeyEventInvalid(e: KeyboardEvent) {
|
||||
return e.target && /^(input|textarea|select)$/i.test((e.target as HTMLElement).tagName);
|
||||
return e.target && /^(input|textarea|select)$/i.test((e.target as HTMLElement).tagName);
|
||||
}
|
||||
|
||||
function allowKey(key: number) {
|
||||
return key === Key.ESCAPE || key === Key.F5 || key === Key.F12 || key === Key.F11 || key === Key.TAB;
|
||||
return key === Key.ESCAPE || key === Key.F5 || key === Key.F12 || key === Key.F11 || key === Key.TAB;
|
||||
}
|
||||
|
||||
function fixKeyCode(key: number) {
|
||||
if (firefox) {
|
||||
if (key === 173) return Key.DASH;
|
||||
if (key === 61) return Key.EQUALS;
|
||||
}
|
||||
if (firefox) {
|
||||
if (key === 173) return Key.DASH;
|
||||
if (key === 61) return Key.EQUALS;
|
||||
}
|
||||
|
||||
return key;
|
||||
return key;
|
||||
}
|
||||
|
||||
const iosKeyToKeyCode: { [key: string]: number | undefined; } = {
|
||||
UIKeyInputEscape: Key.ESCAPE,
|
||||
UIKeyInputUpArrow: Key.UP,
|
||||
UIKeyInputLeftArrow: Key.LEFT,
|
||||
UIKeyInputRightArrow: Key.RIGHT,
|
||||
UIKeyInputDownArrow: Key.DOWN,
|
||||
UIKeyInputEscape: Key.ESCAPE,
|
||||
UIKeyInputUpArrow: Key.UP,
|
||||
UIKeyInputLeftArrow: Key.LEFT,
|
||||
UIKeyInputRightArrow: Key.RIGHT,
|
||||
UIKeyInputDownArrow: Key.DOWN,
|
||||
};
|
||||
|
||||
const iosHandledKeyCodes = [Key.ESCAPE, Key.UP, Key.LEFT, Key.RIGHT, Key.DOWN];
|
||||
|
||||
export class KeyboardController implements InputController {
|
||||
private initialized = false;
|
||||
private stack: number[] = [];
|
||||
constructor(private manager: InputManager) {
|
||||
}
|
||||
initialize() {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
window.addEventListener('keydown', this.keydown);
|
||||
window.addEventListener('keyup', this.keyup);
|
||||
window.addEventListener('blur', this.blur);
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.initialized = false;
|
||||
window.removeEventListener('keydown', this.keydown);
|
||||
window.removeEventListener('keyup', this.keyup);
|
||||
window.removeEventListener('blur', this.blur);
|
||||
this.clear();
|
||||
}
|
||||
update() {
|
||||
}
|
||||
clear() {
|
||||
this.stack.length = 0;
|
||||
}
|
||||
private keydown = (e: KeyboardEvent) => {
|
||||
if (!this.manager.disabledKeyboard && !isKeyEventInvalid(e)) {
|
||||
const code = fixKeyCode(e.keyCode);
|
||||
this.manager.setValue(code, 1);
|
||||
private initialized = false;
|
||||
private stack: number[] = [];
|
||||
constructor(private manager: InputManager) {
|
||||
}
|
||||
initialize() {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
window.addEventListener('keydown', this.keydown);
|
||||
window.addEventListener('keyup', this.keyup);
|
||||
window.addEventListener('blur', this.blur);
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.initialized = false;
|
||||
window.removeEventListener('keydown', this.keydown);
|
||||
window.removeEventListener('keyup', this.keyup);
|
||||
window.removeEventListener('blur', this.blur);
|
||||
this.clear();
|
||||
}
|
||||
update() {
|
||||
}
|
||||
clear() {
|
||||
this.stack.length = 0;
|
||||
}
|
||||
private keydown = (e: KeyboardEvent) => {
|
||||
if (!this.manager.disabledKeyboard && !isKeyEventInvalid(e)) {
|
||||
const code = fixKeyCode(e.keyCode);
|
||||
this.manager.setValue(code, 1);
|
||||
|
||||
if (!allowKey(code)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
if (!allowKey(code)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
if (!includes(this.stack, code) && !includes(iosHandledKeyCodes, code)) {
|
||||
this.stack.push(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
private keyup = (e: KeyboardEvent) => {
|
||||
let code = fixKeyCode(e.keyCode);
|
||||
if (!includes(this.stack, code) && !includes(iosHandledKeyCodes, code)) {
|
||||
this.stack.push(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
private keyup = (e: KeyboardEvent) => {
|
||||
let code = fixKeyCode(e.keyCode);
|
||||
|
||||
// fix keyCode on iOS bluetooth keyboard
|
||||
if (code === 0) {
|
||||
code = iosKeyToKeyCode[e.key] || 0;
|
||||
// fix keyCode on iOS bluetooth keyboard
|
||||
if (code === 0) {
|
||||
code = iosKeyToKeyCode[e.key] || 0;
|
||||
|
||||
if (code === 0) {
|
||||
code = this.stack.pop() || 0;
|
||||
}
|
||||
}
|
||||
if (code === 0) {
|
||||
code = this.stack.pop() || 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.manager.setValue(code, 0)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
if (this.manager.setValue(code, 0)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
removeItem(this.stack, code);
|
||||
}
|
||||
private blur = () => {
|
||||
this.manager.clear();
|
||||
}
|
||||
removeItem(this.stack, code);
|
||||
}
|
||||
private blur = () => {
|
||||
this.manager.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,83 +5,83 @@ import { clamp } from '../../common/utils';
|
||||
const MOUSE_BUTTONS = [Key.MOUSE_BUTTON1, Key.MOUSE_BUTTON3, Key.MOUSE_BUTTON2];
|
||||
|
||||
export class MouseController implements InputController {
|
||||
private initialized = false;
|
||||
private element?: HTMLElement;
|
||||
constructor(private manager: InputManager) {
|
||||
}
|
||||
initialize(element: HTMLElement) {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
this.element = element;
|
||||
element.addEventListener('mousemove', this.mousemove);
|
||||
element.addEventListener('mousedown', this.mousedown);
|
||||
element.addEventListener('mouseup', this.mouseup);
|
||||
element.addEventListener('mousewheel', this.mousewheel);
|
||||
element.addEventListener('contextmenu', this.contextmenu);
|
||||
element.addEventListener('click', this.click);
|
||||
window.addEventListener('blur', this.blur);
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.initialized = false;
|
||||
private initialized = false;
|
||||
private element?: HTMLElement;
|
||||
constructor(private manager: InputManager) {
|
||||
}
|
||||
initialize(element: HTMLElement) {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
this.element = element;
|
||||
element.addEventListener('mousemove', this.mousemove);
|
||||
element.addEventListener('mousedown', this.mousedown);
|
||||
element.addEventListener('mouseup', this.mouseup);
|
||||
element.addEventListener('mousewheel', this.mousewheel);
|
||||
element.addEventListener('contextmenu', this.contextmenu);
|
||||
element.addEventListener('click', this.click);
|
||||
window.addEventListener('blur', this.blur);
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.initialized = false;
|
||||
|
||||
if (this.element) {
|
||||
this.element.removeEventListener('mousemove', this.mousemove);
|
||||
this.element.removeEventListener('mousedown', this.mousedown);
|
||||
this.element.removeEventListener('mouseup', this.mouseup);
|
||||
this.element.removeEventListener('mousewheel', this.mousewheel);
|
||||
this.element.removeEventListener('contextmenu', this.contextmenu);
|
||||
this.element.removeEventListener('click', this.click);
|
||||
this.element = undefined;
|
||||
}
|
||||
if (this.element) {
|
||||
this.element.removeEventListener('mousemove', this.mousemove);
|
||||
this.element.removeEventListener('mousedown', this.mousedown);
|
||||
this.element.removeEventListener('mouseup', this.mouseup);
|
||||
this.element.removeEventListener('mousewheel', this.mousewheel);
|
||||
this.element.removeEventListener('contextmenu', this.contextmenu);
|
||||
this.element.removeEventListener('click', this.click);
|
||||
this.element = undefined;
|
||||
}
|
||||
|
||||
window.removeEventListener('blur', this.blur);
|
||||
}
|
||||
update() {
|
||||
}
|
||||
clear() {
|
||||
}
|
||||
private mousemove = (e: MouseEvent) => {
|
||||
if (this.element) {
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
this.manager.setValue(Key.MOUSE_X, Math.floor(e.clientX - rect.left));
|
||||
this.manager.setValue(Key.MOUSE_Y, Math.floor(e.clientY - rect.top));
|
||||
}
|
||||
}
|
||||
private mousedown = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
window.removeEventListener('blur', this.blur);
|
||||
}
|
||||
update() {
|
||||
}
|
||||
clear() {
|
||||
}
|
||||
private mousemove = (e: MouseEvent) => {
|
||||
if (this.element) {
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
this.manager.setValue(Key.MOUSE_X, Math.floor(e.clientX - rect.left));
|
||||
this.manager.setValue(Key.MOUSE_Y, Math.floor(e.clientY - rect.top));
|
||||
}
|
||||
}
|
||||
private mousedown = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.manager.usingTouch = false;
|
||||
this.manager.usingTouch = false;
|
||||
|
||||
const button = MOUSE_BUTTONS[e.button];
|
||||
const button = MOUSE_BUTTONS[e.button];
|
||||
|
||||
if (button) {
|
||||
this.manager.setValue(button, 1);
|
||||
}
|
||||
}
|
||||
private mouseup = (e: MouseEvent) => {
|
||||
const button = MOUSE_BUTTONS[e.button];
|
||||
if (button) {
|
||||
this.manager.setValue(button, 1);
|
||||
}
|
||||
}
|
||||
private mouseup = (e: MouseEvent) => {
|
||||
const button = MOUSE_BUTTONS[e.button];
|
||||
|
||||
if (button) {
|
||||
this.manager.setValue(button, 0);
|
||||
}
|
||||
}
|
||||
private mousewheel: any = (e: MouseWheelEvent) => {
|
||||
this.manager.addValue(Key.MOUSE_WHEEL_X, clamp(e.deltaX, -1, 1));
|
||||
this.manager.addValue(Key.MOUSE_WHEEL_Y, clamp(e.deltaY, -1, 1));
|
||||
}
|
||||
private contextmenu = (e: Event) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
private click = (e: Event) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
private blur = () => {
|
||||
for (const button of MOUSE_BUTTONS) {
|
||||
this.manager.setValue(button, 0);
|
||||
}
|
||||
}
|
||||
if (button) {
|
||||
this.manager.setValue(button, 0);
|
||||
}
|
||||
}
|
||||
private mousewheel: any = (e: MouseWheelEvent) => {
|
||||
this.manager.addValue(Key.MOUSE_WHEEL_X, clamp(e.deltaX, -1, 1));
|
||||
this.manager.addValue(Key.MOUSE_WHEEL_Y, clamp(e.deltaY, -1, 1));
|
||||
}
|
||||
private contextmenu = (e: Event) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
private click = (e: Event) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
private blur = () => {
|
||||
for (const button of MOUSE_BUTTONS) {
|
||||
this.manager.setValue(button, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+166
-166
@@ -4,200 +4,200 @@ import { setTransform } from '../../common/utils';
|
||||
import { InputManager } from './inputManager';
|
||||
|
||||
function getTouch(e: TouchEvent, id: number) {
|
||||
if (id !== -1) {
|
||||
for (let i = 0; i < e.changedTouches.length; ++i) {
|
||||
const touch = e.changedTouches.item(i);
|
||||
if (id !== -1) {
|
||||
for (let i = 0; i < e.changedTouches.length; ++i) {
|
||||
const touch = e.changedTouches.item(i);
|
||||
|
||||
if (touch && touch.identifier === id) {
|
||||
return touch;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (touch && touch.identifier === id) {
|
||||
return touch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const TOUCH_DEADZONE = 15;
|
||||
const TOUCH_MAX = 100;
|
||||
|
||||
export class TouchController implements InputController {
|
||||
private initialized = false;
|
||||
private touchId = -1;
|
||||
private touch2Id = -1;
|
||||
private touchStart: Point = { x: 0, y: 0 };
|
||||
private touchCurrent: Point = { x: 0, y: 0 };
|
||||
private touchIsDrag = false;
|
||||
private tapInvalidated = false;
|
||||
private origin?: HTMLElement;
|
||||
private position?: HTMLElement;
|
||||
private originShown = false;
|
||||
private originTransform?: string;
|
||||
private positionShown = false;
|
||||
private positionTransform?: string;
|
||||
private element?: HTMLElement;
|
||||
constructor(private manager: InputManager) {
|
||||
}
|
||||
initialize(element: HTMLElement) {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
this.element = element;
|
||||
this.origin = document.getElementById('touch-origin')!;
|
||||
this.position = document.getElementById('touch-position')!;
|
||||
private initialized = false;
|
||||
private touchId = -1;
|
||||
private touch2Id = -1;
|
||||
private touchStart: Point = { x: 0, y: 0 };
|
||||
private touchCurrent: Point = { x: 0, y: 0 };
|
||||
private touchIsDrag = false;
|
||||
private tapInvalidated = false;
|
||||
private origin?: HTMLElement;
|
||||
private position?: HTMLElement;
|
||||
private originShown = false;
|
||||
private originTransform?: string;
|
||||
private positionShown = false;
|
||||
private positionTransform?: string;
|
||||
private element?: HTMLElement;
|
||||
constructor(private manager: InputManager) {
|
||||
}
|
||||
initialize(element: HTMLElement) {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
this.element = element;
|
||||
this.origin = document.getElementById('touch-origin')!;
|
||||
this.position = document.getElementById('touch-position')!;
|
||||
|
||||
element.addEventListener('touchstart', this.touchstart);
|
||||
element.addEventListener('touchmove', this.touchmove);
|
||||
element.addEventListener('touchend', this.touchend);
|
||||
window.addEventListener('touchend', this.blur);
|
||||
window.addEventListener('blur', this.blur);
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.initialized = false;
|
||||
element.addEventListener('touchstart', this.touchstart);
|
||||
element.addEventListener('touchmove', this.touchmove);
|
||||
element.addEventListener('touchend', this.touchend);
|
||||
window.addEventListener('touchend', this.blur);
|
||||
window.addEventListener('blur', this.blur);
|
||||
}
|
||||
}
|
||||
release() {
|
||||
this.initialized = false;
|
||||
|
||||
if (this.element) {
|
||||
this.element.removeEventListener('touchstart', this.touchstart);
|
||||
this.element.removeEventListener('touchmove', this.touchmove);
|
||||
this.element.removeEventListener('touchend', this.touchend);
|
||||
this.element = undefined;
|
||||
}
|
||||
if (this.element) {
|
||||
this.element.removeEventListener('touchstart', this.touchstart);
|
||||
this.element.removeEventListener('touchmove', this.touchmove);
|
||||
this.element.removeEventListener('touchend', this.touchend);
|
||||
this.element = undefined;
|
||||
}
|
||||
|
||||
window.removeEventListener('touchend', this.blur);
|
||||
window.removeEventListener('blur', this.blur);
|
||||
}
|
||||
update() {
|
||||
const showOrigin = this.touchIsDrag && this.touchId !== -1;
|
||||
const showPosition = this.touchId !== -1;
|
||||
window.removeEventListener('touchend', this.blur);
|
||||
window.removeEventListener('blur', this.blur);
|
||||
}
|
||||
update() {
|
||||
const showOrigin = this.touchIsDrag && this.touchId !== -1;
|
||||
const showPosition = this.touchId !== -1;
|
||||
|
||||
if (this.origin && this.position) {
|
||||
if (this.originShown !== showOrigin) {
|
||||
this.originShown = showOrigin;
|
||||
this.origin.style.display = showOrigin ? 'block' : 'none';
|
||||
}
|
||||
if (this.origin && this.position) {
|
||||
if (this.originShown !== showOrigin) {
|
||||
this.originShown = showOrigin;
|
||||
this.origin.style.display = showOrigin ? 'block' : 'none';
|
||||
}
|
||||
|
||||
if (this.positionShown !== showPosition) {
|
||||
this.positionShown = showPosition;
|
||||
this.position.style.display = showPosition ? 'block' : 'none';
|
||||
}
|
||||
if (this.positionShown !== showPosition) {
|
||||
this.positionShown = showPosition;
|
||||
this.position.style.display = showPosition ? 'block' : 'none';
|
||||
}
|
||||
|
||||
if (showOrigin) {
|
||||
const transform = `translate3d(${this.touchStart.x - 50}px, ${this.touchStart.y - 50}px, 0px)`;
|
||||
if (showOrigin) {
|
||||
const transform = `translate3d(${this.touchStart.x - 50}px, ${this.touchStart.y - 50}px, 0px)`;
|
||||
|
||||
if (this.originTransform !== transform) {
|
||||
this.originTransform = transform;
|
||||
setTransform(this.origin, transform);
|
||||
}
|
||||
}
|
||||
if (this.originTransform !== transform) {
|
||||
this.originTransform = transform;
|
||||
setTransform(this.origin, transform);
|
||||
}
|
||||
}
|
||||
|
||||
if (showPosition) {
|
||||
const transform = `translate3d(${this.touchCurrent.x - 25}px, ${this.touchCurrent.y - 25}px, 0px)`;
|
||||
if (showPosition) {
|
||||
const transform = `translate3d(${this.touchCurrent.x - 25}px, ${this.touchCurrent.y - 25}px, 0px)`;
|
||||
|
||||
if (this.positionTransform !== transform) {
|
||||
this.positionTransform = transform;
|
||||
setTransform(this.position, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clear() {
|
||||
}
|
||||
private reset() {
|
||||
this.touch2Id = -1;
|
||||
this.resetTouch();
|
||||
}
|
||||
private resetTouch() {
|
||||
this.touchId = -1;
|
||||
this.touchStart = this.touchCurrent = { x: 0, y: 0 };
|
||||
this.touchIsDrag = false;
|
||||
this.manager.setValue(Key.TOUCH, 0);
|
||||
this.updateInput();
|
||||
}
|
||||
private updateInput() {
|
||||
const dy = this.touchStart.y - this.touchCurrent.y;
|
||||
const dx = this.touchStart.x - this.touchCurrent.x;
|
||||
const theta = Math.atan2(dy, dx);
|
||||
const dist = Math.sqrt(dy * dy + dx * dx);
|
||||
if (this.positionTransform !== transform) {
|
||||
this.positionTransform = transform;
|
||||
setTransform(this.position, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clear() {
|
||||
}
|
||||
private reset() {
|
||||
this.touch2Id = -1;
|
||||
this.resetTouch();
|
||||
}
|
||||
private resetTouch() {
|
||||
this.touchId = -1;
|
||||
this.touchStart = this.touchCurrent = { x: 0, y: 0 };
|
||||
this.touchIsDrag = false;
|
||||
this.manager.setValue(Key.TOUCH, 0);
|
||||
this.updateInput();
|
||||
}
|
||||
private updateInput() {
|
||||
const dy = this.touchStart.y - this.touchCurrent.y;
|
||||
const dx = this.touchStart.x - this.touchCurrent.x;
|
||||
const theta = Math.atan2(dy, dx);
|
||||
const dist = Math.sqrt(dy * dy + dx * dx);
|
||||
|
||||
if (dist > TOUCH_DEADZONE) {
|
||||
const scaledDist = Math.min((dist - TOUCH_DEADZONE) / (TOUCH_MAX - TOUCH_DEADZONE), 1);
|
||||
this.touchIsDrag = true;
|
||||
this.manager.setValue(Key.GAMEPAD_AXIS1_X, -Math.cos(theta) * scaledDist);
|
||||
this.manager.setValue(Key.GAMEPAD_AXIS1_Y, -Math.sin(theta) * scaledDist);
|
||||
} else {
|
||||
this.manager.setValue(Key.GAMEPAD_AXIS1_X, 0);
|
||||
this.manager.setValue(Key.GAMEPAD_AXIS1_Y, 0);
|
||||
}
|
||||
}
|
||||
private touchstart = (e: any) => {
|
||||
e.cancellable && e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (dist > TOUCH_DEADZONE) {
|
||||
const scaledDist = Math.min((dist - TOUCH_DEADZONE) / (TOUCH_MAX - TOUCH_DEADZONE), 1);
|
||||
this.touchIsDrag = true;
|
||||
this.manager.setValue(Key.GAMEPAD_AXIS1_X, -Math.cos(theta) * scaledDist);
|
||||
this.manager.setValue(Key.GAMEPAD_AXIS1_Y, -Math.sin(theta) * scaledDist);
|
||||
} else {
|
||||
this.manager.setValue(Key.GAMEPAD_AXIS1_X, 0);
|
||||
this.manager.setValue(Key.GAMEPAD_AXIS1_Y, 0);
|
||||
}
|
||||
}
|
||||
private touchstart = (e: any) => {
|
||||
e.cancellable && e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.manager.usingTouch = true;
|
||||
this.manager.usingTouch = true;
|
||||
|
||||
if (this.touchId === -1) {
|
||||
const touch = e.changedTouches.item(0);
|
||||
if (this.touchId === -1) {
|
||||
const touch = e.changedTouches.item(0);
|
||||
|
||||
if (touch) {
|
||||
this.tapInvalidated = false;
|
||||
this.touchId = touch.identifier;
|
||||
this.touchStart = this.touchCurrent = this.getTouchXY(touch);
|
||||
this.manager.setValue(Key.MOUSE_X, this.touchStart.x);
|
||||
this.manager.setValue(Key.MOUSE_Y, this.touchStart.y);
|
||||
this.manager.setValue(Key.TOUCH, 1);
|
||||
}
|
||||
} else if (this.touch2Id === -1) {
|
||||
const touch = e.changedTouches.item(0);
|
||||
if (touch) {
|
||||
this.tapInvalidated = false;
|
||||
this.touchId = touch.identifier;
|
||||
this.touchStart = this.touchCurrent = this.getTouchXY(touch);
|
||||
this.manager.setValue(Key.MOUSE_X, this.touchStart.x);
|
||||
this.manager.setValue(Key.MOUSE_Y, this.touchStart.y);
|
||||
this.manager.setValue(Key.TOUCH, 1);
|
||||
}
|
||||
} else if (this.touch2Id === -1) {
|
||||
const touch = e.changedTouches.item(0);
|
||||
|
||||
if (touch) {
|
||||
this.tapInvalidated = true;
|
||||
this.touch2Id = touch.identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
private touchmove = (e: any) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (touch) {
|
||||
this.tapInvalidated = true;
|
||||
this.touch2Id = touch.identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
private touchmove = (e: any) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const touch = getTouch(e, this.touchId);
|
||||
const touch = getTouch(e, this.touchId);
|
||||
|
||||
if (touch) {
|
||||
this.touchCurrent = this.getTouchXY(touch);
|
||||
this.manager.setValue(Key.MOUSE_X, this.touchCurrent.x);
|
||||
this.manager.setValue(Key.MOUSE_Y, this.touchCurrent.y);
|
||||
this.updateInput();
|
||||
}
|
||||
}
|
||||
private touchend = (e: any) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (touch) {
|
||||
this.touchCurrent = this.getTouchXY(touch);
|
||||
this.manager.setValue(Key.MOUSE_X, this.touchCurrent.x);
|
||||
this.manager.setValue(Key.MOUSE_Y, this.touchCurrent.y);
|
||||
this.updateInput();
|
||||
}
|
||||
}
|
||||
private touchend = (e: any) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const touch = getTouch(e, this.touchId);
|
||||
const touch = getTouch(e, this.touchId);
|
||||
|
||||
if (touch) {
|
||||
if (!this.touchIsDrag && !this.tapInvalidated) {
|
||||
this.manager.setValue(Key.MOUSE_X, this.touchStart.x);
|
||||
this.manager.setValue(Key.MOUSE_Y, this.touchStart.y);
|
||||
this.manager.setValue(Key.TOUCH_CLICK, 1);
|
||||
}
|
||||
if (touch) {
|
||||
if (!this.touchIsDrag && !this.tapInvalidated) {
|
||||
this.manager.setValue(Key.MOUSE_X, this.touchStart.x);
|
||||
this.manager.setValue(Key.MOUSE_Y, this.touchStart.y);
|
||||
this.manager.setValue(Key.TOUCH_CLICK, 1);
|
||||
}
|
||||
|
||||
this.resetTouch();
|
||||
}
|
||||
this.resetTouch();
|
||||
}
|
||||
|
||||
const touch2 = getTouch(e, this.touch2Id);
|
||||
const touch2 = getTouch(e, this.touch2Id);
|
||||
|
||||
if (touch2) {
|
||||
this.manager.setValue(Key.TOUCH_SECOND_CLICK, 1);
|
||||
this.touch2Id = -1;
|
||||
}
|
||||
}
|
||||
private blur = () => {
|
||||
this.reset();
|
||||
}
|
||||
private getTouchXY(touch: Touch) {
|
||||
const { left, top } = this.element!.getBoundingClientRect();
|
||||
if (touch2) {
|
||||
this.manager.setValue(Key.TOUCH_SECOND_CLICK, 1);
|
||||
this.touch2Id = -1;
|
||||
}
|
||||
}
|
||||
private blur = () => {
|
||||
this.reset();
|
||||
}
|
||||
private getTouchXY(touch: Touch) {
|
||||
const { left, top } = this.element!.getBoundingClientRect();
|
||||
|
||||
return {
|
||||
x: touch.clientX - left,
|
||||
y: touch.clientY - top,
|
||||
};
|
||||
}
|
||||
return {
|
||||
x: touch.clientX - left,
|
||||
y: touch.clientY - top,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+24
-24
@@ -3,42 +3,42 @@ import { PartyMember, PartyInfo, Pony } from '../common/interfaces';
|
||||
import { PonyTownGame } from './game';
|
||||
|
||||
export function updateParty(current: PartyInfo | undefined, info: PartyMember[] | undefined): PartyInfo | undefined {
|
||||
if (!info || !info.length) {
|
||||
return undefined;
|
||||
} else {
|
||||
const party = current || {
|
||||
leaderId: 0,
|
||||
members: [],
|
||||
};
|
||||
if (!info || !info.length) {
|
||||
return undefined;
|
||||
} else {
|
||||
const party = current || {
|
||||
leaderId: 0,
|
||||
members: [],
|
||||
};
|
||||
|
||||
remove(party.members, p => !info.some(m => p.id === m.id));
|
||||
remove(party.members, p => !info.some(m => p.id === m.id));
|
||||
|
||||
info.forEach(m => {
|
||||
const existing = party.members.find(x => m.id === x.id);
|
||||
info.forEach(m => {
|
||||
const existing = party.members.find(x => m.id === x.id);
|
||||
|
||||
if (existing) {
|
||||
Object.assign(existing, m);
|
||||
} else {
|
||||
party.members.push(m);
|
||||
}
|
||||
if (existing) {
|
||||
Object.assign(existing, m);
|
||||
} else {
|
||||
party.members.push(m);
|
||||
}
|
||||
|
||||
if (m.leader) {
|
||||
party.leaderId = m.id;
|
||||
}
|
||||
});
|
||||
if (m.leader) {
|
||||
party.leaderId = m.id;
|
||||
}
|
||||
});
|
||||
|
||||
return party;
|
||||
}
|
||||
return party;
|
||||
}
|
||||
}
|
||||
|
||||
export function isPonyInParty(party: PartyInfo | undefined, pony: Pony, pending: boolean) {
|
||||
return !!party && party.members.some(m => m.pony === pony && (pending || !m.pending));
|
||||
return !!party && party.members.some(m => m.pony === pony && (pending || !m.pending));
|
||||
}
|
||||
|
||||
export function isPartyLeader(game: PonyTownGame): boolean {
|
||||
return game.party !== undefined && game.player !== undefined && game.player.id === game.party.leaderId;
|
||||
return game.party !== undefined && game.player !== undefined && game.player.id === game.party.leaderId;
|
||||
}
|
||||
|
||||
export function isInParty(game: PonyTownGame): boolean {
|
||||
return game.party !== undefined && game.party.members.length > 0;
|
||||
return game.party !== undefined && game.party.members.length > 0;
|
||||
}
|
||||
|
||||
+165
-165
@@ -2,8 +2,8 @@ import { isCommand, processCommand, hasFlag, includes, point } from '../common/u
|
||||
import { canPonyLie, canPonyFlyUp, canPonyStand, canPonySit, doBoopPonyAction } from '../common/pony';
|
||||
import { PonyTownGame } from './game';
|
||||
import {
|
||||
setPonyState, canBoop, isPonyLying, isPonyFlying, isPonyStanding, isPonySitting, getInteractBounds,
|
||||
isFacingRight, closestEntity, entityInRange
|
||||
setPonyState, canBoop, isPonyLying, isPonyFlying, isPonyStanding, isPonySitting, getInteractBounds,
|
||||
isFacingRight, closestEntity, entityInRange
|
||||
} from '../common/entityUtils';
|
||||
import { EntityState, Action, Pony, ChatType, EntityFlags, Point, TileType } from '../common/interfaces';
|
||||
import { FLY_DELAY } from '../common/constants';
|
||||
@@ -14,216 +14,216 @@ import { pointToWorld, roundPositionX, roundPositionY } from '../common/position
|
||||
import { hammer, shovel } from '../common/entities';
|
||||
|
||||
export function handleActionCommand(message: string, game: PonyTownGame): boolean {
|
||||
if (isCommand(message)) {
|
||||
const { command = '' } = processCommand(message);
|
||||
const player = game.player;
|
||||
if (isCommand(message)) {
|
||||
const { command = '' } = processCommand(message);
|
||||
const player = game.player;
|
||||
|
||||
if (DEVELOPMENT) {
|
||||
if (command === 'spammessages') {
|
||||
let i = 0;
|
||||
setInterval(() => game.send(server => server.say(0, randomString(5) + ` #${i++}`, ChatType.Say)), 100);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (DEVELOPMENT) {
|
||||
if (command === 'spammessages') {
|
||||
let i = 0;
|
||||
setInterval(() => game.send(server => server.say(0, randomString(5) + ` #${i++}`, ChatType.Say)), 100);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
switch (command.toLowerCase()) {
|
||||
case 'testerrorreporting':
|
||||
throw new Error('test error');
|
||||
case 'disablepixelratio':
|
||||
game.togglePixelRatio();
|
||||
return true;
|
||||
case 'lie':
|
||||
case 'lay':
|
||||
if (player) {
|
||||
if (isPonyLying(player)) {
|
||||
sitAction(player, game);
|
||||
} else {
|
||||
lieAction(player, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case 'sit':
|
||||
if (player) {
|
||||
if (isPonyFlying(player)) {
|
||||
standAction(player, game);
|
||||
} else {
|
||||
sitAction(player, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case 'stand':
|
||||
if (player) {
|
||||
standAction(player, game);
|
||||
}
|
||||
return true;
|
||||
case 'fly':
|
||||
if (player) {
|
||||
if (isPonyFlying(player)) {
|
||||
standAction(player, game);
|
||||
} else {
|
||||
flyAction(player, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
switch (command.toLowerCase()) {
|
||||
case 'testerrorreporting':
|
||||
throw new Error('test error');
|
||||
case 'disablepixelratio':
|
||||
game.togglePixelRatio();
|
||||
return true;
|
||||
case 'lie':
|
||||
case 'lay':
|
||||
if (player) {
|
||||
if (isPonyLying(player)) {
|
||||
sitAction(player, game);
|
||||
} else {
|
||||
lieAction(player, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case 'sit':
|
||||
if (player) {
|
||||
if (isPonyFlying(player)) {
|
||||
standAction(player, game);
|
||||
} else {
|
||||
sitAction(player, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case 'stand':
|
||||
if (player) {
|
||||
standAction(player, game);
|
||||
}
|
||||
return true;
|
||||
case 'fly':
|
||||
if (player) {
|
||||
if (isPonyFlying(player)) {
|
||||
standAction(player, game);
|
||||
} else {
|
||||
flyAction(player, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function upAction(game: PonyTownGame) {
|
||||
const player = game.player;
|
||||
const player = game.player;
|
||||
|
||||
if (player) {
|
||||
if (isPonyLying(player)) {
|
||||
sitAction(player, game);
|
||||
} else if (isPonySitting(player)) {
|
||||
standAction(player, game);
|
||||
} else if (isPonyStanding(player)) {
|
||||
flyAction(player, game);
|
||||
}
|
||||
}
|
||||
if (player) {
|
||||
if (isPonyLying(player)) {
|
||||
sitAction(player, game);
|
||||
} else if (isPonySitting(player)) {
|
||||
standAction(player, game);
|
||||
} else if (isPonyStanding(player)) {
|
||||
flyAction(player, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function downAction(game: PonyTownGame) {
|
||||
const player = game.player;
|
||||
const player = game.player;
|
||||
|
||||
if (player) {
|
||||
if (isPonySitting(player)) {
|
||||
lieAction(player, game);
|
||||
} else if (isPonyStanding(player)) {
|
||||
sitAction(player, game);
|
||||
} else if (isPonyFlying(player)) {
|
||||
standAction(player, game);
|
||||
}
|
||||
}
|
||||
if (player) {
|
||||
if (isPonySitting(player)) {
|
||||
lieAction(player, game);
|
||||
} else if (isPonyStanding(player)) {
|
||||
sitAction(player, game);
|
||||
} else if (isPonyFlying(player)) {
|
||||
standAction(player, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function sitAction(player: Pony, game: PonyTownGame) {
|
||||
if (canPonySit(player, game.map) && game.send(server => server.action(Action.Sit))) {
|
||||
player.state = setPonyState(player.state, EntityState.PonySitting);
|
||||
game.stateOverride = EntityState.PonySitting;
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
if (canPonySit(player, game.map) && game.send(server => server.action(Action.Sit))) {
|
||||
player.state = setPonyState(player.state, EntityState.PonySitting);
|
||||
game.stateOverride = EntityState.PonySitting;
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
}
|
||||
|
||||
export function standAction(player: Pony, game: PonyTownGame) {
|
||||
if (canPonyStand(player, game.map) && game.send(server => server.action(Action.Stand))) {
|
||||
player.state = setPonyState(player.state, EntityState.PonyStanding);
|
||||
game.stateOverride = EntityState.PonyStanding;
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
if (canPonyStand(player, game.map) && game.send(server => server.action(Action.Stand))) {
|
||||
player.state = setPonyState(player.state, EntityState.PonyStanding);
|
||||
game.stateOverride = EntityState.PonyStanding;
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
}
|
||||
|
||||
export function lieAction(player: Pony, game: PonyTownGame) {
|
||||
if (canPonyLie(player, game.map) && game.send(server => server.action(Action.Lie))) {
|
||||
player.state = setPonyState(player.state, EntityState.PonyLying);
|
||||
game.stateOverride = EntityState.PonyLying;
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
if (canPonyLie(player, game.map) && game.send(server => server.action(Action.Lie))) {
|
||||
player.state = setPonyState(player.state, EntityState.PonyLying);
|
||||
game.stateOverride = EntityState.PonyLying;
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
}
|
||||
|
||||
export function flyAction(player: Pony, game: PonyTownGame) {
|
||||
if (canPonyFlyUp(player) && game.send(server => server.action(Action.Fly))) {
|
||||
player.state = setPonyState(player.state, EntityState.PonyFlying);
|
||||
player.inTheAirDelay = FLY_DELAY;
|
||||
game.stateOverride = EntityState.PonyFlying;
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
if (canPonyFlyUp(player) && game.send(server => server.action(Action.Fly))) {
|
||||
player.state = setPonyState(player.state, EntityState.PonyFlying);
|
||||
player.inTheAirDelay = FLY_DELAY;
|
||||
game.stateOverride = EntityState.PonyFlying;
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
}
|
||||
|
||||
export function boopAction(game: PonyTownGame) {
|
||||
if (game.player && canBoop(game.player) && game.send(server => server.action(Action.Boop))) {
|
||||
doBoopPonyAction(game, game.player);
|
||||
}
|
||||
if (game.player && canBoop(game.player) && game.send(server => server.action(Action.Boop))) {
|
||||
doBoopPonyAction(game, game.player);
|
||||
}
|
||||
}
|
||||
|
||||
export function turnHeadAction(game: PonyTownGame) {
|
||||
if (game.player && game.send(server => server.action(Action.TurnHead))) {
|
||||
game.player.state = game.player.state ^ EntityState.HeadTurned;
|
||||
game.headTurnedOverride = hasFlag(game.player.state, EntityState.HeadTurned);
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
if (game.player && game.send(server => server.action(Action.TurnHead))) {
|
||||
game.player.state = game.player.state ^ EntityState.HeadTurned;
|
||||
game.headTurnedOverride = hasFlag(game.player.state, EntityState.HeadTurned);
|
||||
game.onActionsUpdate.next();
|
||||
}
|
||||
}
|
||||
|
||||
export function interact(game: PonyTownGame, shift: boolean) {
|
||||
const player = game.player;
|
||||
const player = game.player;
|
||||
|
||||
if (player) {
|
||||
const bounds = getInteractBounds(player);
|
||||
const entities = pickEntitiesByRect(game.map, bounds, true, false);
|
||||
const center = centerPoint(bounds);
|
||||
center.x += (bounds.w / 4) * (isFacingRight(player) ? -1 : 1);
|
||||
const entity = closestEntity(pointToWorld(center), entities);
|
||||
if (player) {
|
||||
const bounds = getInteractBounds(player);
|
||||
const entities = pickEntitiesByRect(game.map, bounds, true, false);
|
||||
const center = centerPoint(bounds);
|
||||
center.x += (bounds.w / 4) * (isFacingRight(player) ? -1 : 1);
|
||||
const entity = closestEntity(pointToWorld(center), entities);
|
||||
|
||||
if (entity && entityInRange(entity, player)) {
|
||||
game.send(server => server.interact(entity.id));
|
||||
} else if (player.hold === hammer.type) {
|
||||
game.changePlaceEntity(shift);
|
||||
} else if (player.hold === shovel.type) {
|
||||
game.changePlaceTile(shift);
|
||||
} else if (player.ponyState.holding && hasFlag(player.ponyState.holding.flags, EntityFlags.Usable)) {
|
||||
game.send(server => server.use());
|
||||
}
|
||||
}
|
||||
if (entity && entityInRange(entity, player)) {
|
||||
game.send(server => server.interact(entity.id));
|
||||
} else if (player.hold === hammer.type) {
|
||||
game.changePlaceEntity(shift);
|
||||
} else if (player.hold === shovel.type) {
|
||||
game.changePlaceTile(shift);
|
||||
} else if (player.ponyState.holding && hasFlag(player.ponyState.holding.flags, EntityFlags.Usable)) {
|
||||
game.send(server => server.use());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function toggleWall(game: PonyTownGame, hover: Point) {
|
||||
const x = hover.x | 0;
|
||||
const y = hover.y | 0;
|
||||
const dx = hover.x - x;
|
||||
const dy = hover.y - y;
|
||||
const x = hover.x | 0;
|
||||
const y = hover.y | 0;
|
||||
const dx = hover.x - x;
|
||||
const dy = hover.y - y;
|
||||
|
||||
if (dx > dy) {
|
||||
if ((dx + dy) < 1) {
|
||||
game.send(server => server.changeTile(x, y, TileType.WallH));
|
||||
} else {
|
||||
game.send(server => server.changeTile(x + 1, y, TileType.WallV));
|
||||
}
|
||||
} else {
|
||||
if ((dx + dy) < 1) {
|
||||
game.send(server => server.changeTile(x, y, TileType.WallV));
|
||||
} else {
|
||||
game.send(server => server.changeTile(x, y + 1, TileType.WallH));
|
||||
}
|
||||
}
|
||||
if (dx > dy) {
|
||||
if ((dx + dy) < 1) {
|
||||
game.send(server => server.changeTile(x, y, TileType.WallH));
|
||||
} else {
|
||||
game.send(server => server.changeTile(x + 1, y, TileType.WallV));
|
||||
}
|
||||
} else {
|
||||
if ((dx + dy) < 1) {
|
||||
game.send(server => server.changeTile(x, y, TileType.WallV));
|
||||
} else {
|
||||
game.send(server => server.changeTile(x, y + 1, TileType.WallH));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function editorSelectEntities(game: PonyTownGame, hover: Point, shift: boolean) {
|
||||
game.apply(() => {
|
||||
const entities = pickAnyEntities(game.map, hover);
|
||||
game.apply(() => {
|
||||
const entities = pickAnyEntities(game.map, hover);
|
||||
|
||||
if (shift) {
|
||||
const entity = entities.filter(e => !includes(game.editor.selectedEntities, e))[0];
|
||||
entity && game.editor.selectedEntities.push(entity);
|
||||
} else {
|
||||
const index = entities.findIndex(e => includes(game.editor.selectedEntities, e));
|
||||
const entity = entities[(index + 1) % entities.length];
|
||||
game.editor.selectedEntities = entity ? [entity] : [];
|
||||
}
|
||||
});
|
||||
if (shift) {
|
||||
const entity = entities.filter(e => !includes(game.editor.selectedEntities, e))[0];
|
||||
entity && game.editor.selectedEntities.push(entity);
|
||||
} else {
|
||||
const index = entities.findIndex(e => includes(game.editor.selectedEntities, e));
|
||||
const entity = entities[(index + 1) % entities.length];
|
||||
game.editor.selectedEntities = entity ? [entity] : [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function editorDragEntities(game: PonyTownGame, hover: Point, buttonPressed: boolean) {
|
||||
if (buttonPressed) {
|
||||
const dx = hover.x - game.editor.draggingStart.x;
|
||||
const dy = hover.y - game.editor.draggingStart.y;
|
||||
if (buttonPressed) {
|
||||
const dx = hover.x - game.editor.draggingStart.x;
|
||||
const dy = hover.y - game.editor.draggingStart.y;
|
||||
|
||||
game.editor.selectedEntities.forEach(e => {
|
||||
e.x = roundPositionX(e.draggingStart!.x + dx);
|
||||
e.y = roundPositionY(e.draggingStart!.y + dy);
|
||||
});
|
||||
} else {
|
||||
game.apply(() => game.editor.draggingEntities = false);
|
||||
game.send(server => server.editorAction({
|
||||
type: 'move',
|
||||
entities: game.editor.selectedEntities.map(({ id, x, y }) => ({ id, x, y })),
|
||||
}));
|
||||
}
|
||||
game.editor.selectedEntities.forEach(e => {
|
||||
e.x = roundPositionX(e.draggingStart!.x + dx);
|
||||
e.y = roundPositionY(e.draggingStart!.y + dy);
|
||||
});
|
||||
} else {
|
||||
game.apply(() => game.editor.draggingEntities = false);
|
||||
game.send(server => server.editorAction({
|
||||
type: 'move',
|
||||
entities: game.editor.selectedEntities.map(({ id, x, y }) => ({ id, x, y })),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export function editorMoveEntities(game: PonyTownGame, hover: Point) {
|
||||
game.editor.draggingEntities = true;
|
||||
game.editor.draggingStart = hover;
|
||||
game.editor.selectedEntities.forEach(e => e.draggingStart = point(e.x, e.y));
|
||||
game.editor.draggingEntities = true;
|
||||
game.editor.draggingStart = hover;
|
||||
game.editor.selectedEntities.forEach(e => e.draggingStart = point(e.x, e.y));
|
||||
}
|
||||
|
||||
+15
-15
@@ -2,32 +2,32 @@
|
||||
|
||||
// Safari <= 8.4, Android
|
||||
try {
|
||||
if (!('performance' in window && 'now' in performance)) {
|
||||
(window as any).performance = Date;
|
||||
}
|
||||
if (!('performance' in window && 'now' in performance)) {
|
||||
(window as any).performance = Date;
|
||||
}
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
if (!('getGamepads' in navigator)) {
|
||||
(window.navigator as any).getGamepads = () => [];
|
||||
}
|
||||
if (!('getGamepads' in navigator)) {
|
||||
(window.navigator as any).getGamepads = () => [];
|
||||
}
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
if (!('requestAnimationFrame' in window)) {
|
||||
(window as any).requestAnimationFrame = (callback: any) => setTimeout(() => callback(performance.now()), 1000 / 60) as any;
|
||||
}
|
||||
if (!('requestAnimationFrame' in window)) {
|
||||
(window as any).requestAnimationFrame = (callback: any) => setTimeout(() => callback(performance.now()), 1000 / 60) as any;
|
||||
}
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
if (!('cancelAnimationFrame' in window)) {
|
||||
(window as any).cancelAnimationFrame = clearTimeout;
|
||||
}
|
||||
if (!('cancelAnimationFrame' in window)) {
|
||||
(window as any).cancelAnimationFrame = clearTimeout;
|
||||
}
|
||||
} catch { }
|
||||
|
||||
// IE <= 10
|
||||
try {
|
||||
if (!('devicePixelRatio' in window)) {
|
||||
(window as any).devicePixelRatio = 1;
|
||||
}
|
||||
if (!('devicePixelRatio' in window)) {
|
||||
(window as any).devicePixelRatio = 1;
|
||||
}
|
||||
} catch { }
|
||||
|
||||
+367
-367
@@ -4,459 +4,459 @@ import { repeat, flatten } from '../common/utils';
|
||||
// body animations
|
||||
|
||||
export function createBodyFrame([
|
||||
body = 0, head = 0, wing = 0, tail = 0,
|
||||
frontLeg = 0, frontFarLeg = 0, backLeg = 0, backFarLeg = 0,
|
||||
bodyX = 0, bodyY = 0, headX = 0, headY = 0,
|
||||
frontLegX = 0, frontLegY = 0, frontFarLegX = 0, frontFarLegY = 0,
|
||||
backLegX = 0, backLegY = 0, backFarLegX = 0, backFarLegY = 0
|
||||
body = 0, head = 0, wing = 0, tail = 0,
|
||||
frontLeg = 0, frontFarLeg = 0, backLeg = 0, backFarLeg = 0,
|
||||
bodyX = 0, bodyY = 0, headX = 0, headY = 0,
|
||||
frontLegX = 0, frontLegY = 0, frontFarLegX = 0, frontFarLegY = 0,
|
||||
backLegX = 0, backLegY = 0, backFarLegX = 0, backFarLegY = 0
|
||||
]: number[]): Readonly<BodyAnimationFrame> {
|
||||
return {
|
||||
body, head, wing, tail,
|
||||
frontLeg, frontFarLeg, backLeg, backFarLeg,
|
||||
bodyX, bodyY, headX, headY,
|
||||
frontLegX, frontLegY, frontFarLegX, frontFarLegY,
|
||||
backLegX, backLegY, backFarLegX, backFarLegY
|
||||
};
|
||||
return {
|
||||
body, head, wing, tail,
|
||||
frontLeg, frontFarLeg, backLeg, backFarLeg,
|
||||
bodyX, bodyY, headX, headY,
|
||||
frontLegX, frontLegY, frontFarLegX, frontFarLegY,
|
||||
backLegX, backLegY, backFarLegX, backFarLegY
|
||||
};
|
||||
}
|
||||
|
||||
export function createBodyAnimation(
|
||||
name: string, fps: number, loop: boolean, frames: number[][], shadowOffsets?: number[][]
|
||||
name: string, fps: number, loop: boolean, frames: number[][], shadowOffsets?: number[][]
|
||||
): Readonly<BodyAnimation> {
|
||||
if (shadowOffsets && shadowOffsets.length !== frames.length) {
|
||||
throw new Error(`Incorrect frame count for shadowOffsets for ${name}`);
|
||||
}
|
||||
if (shadowOffsets && shadowOffsets.length !== frames.length) {
|
||||
throw new Error(`Incorrect frame count for shadowOffsets for ${name}`);
|
||||
}
|
||||
|
||||
const shadow = shadowOffsets && shadowOffsets.map<BodyShadow>(([frame, offset]) => ({ frame, offset }));
|
||||
const shadow = shadowOffsets && shadowOffsets.map<BodyShadow>(([frame, offset]) => ({ frame, offset }));
|
||||
|
||||
return { name, loop, fps, frames: frames.map(createBodyFrame), shadow };
|
||||
return { name, loop, fps, frames: frames.map(createBodyFrame), shadow };
|
||||
}
|
||||
|
||||
export const stand = createBodyAnimation('stand', 24, true, [
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
]);
|
||||
|
||||
export const swim = createBodyAnimation('swim', 4, true, [
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 14],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 12],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 13]
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 14],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 12],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 13]
|
||||
]);
|
||||
|
||||
export const trotToSwim = createBodyAnimation('trot-to-swim', 24, false, [
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 2],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 8],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 10],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 16]
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 2],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 8],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 10],
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 16]
|
||||
]);
|
||||
|
||||
export const swimToTrot = createBodyAnimation('swim-to-trot', 24, false, [
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 12],
|
||||
[1, 1, 0, 0, 12, 3, 4, 23, 0, 8],
|
||||
[1, 1, 0, 0, 14, 26, 3, 24, 0, 4],
|
||||
[1, 1, 0, 0, 18, 27, 2, 5]
|
||||
[1, 1, 0, 0, 8, 10, 6, 5, 0, 12],
|
||||
[1, 1, 0, 0, 12, 3, 4, 23, 0, 8],
|
||||
[1, 1, 0, 0, 14, 26, 3, 24, 0, 4],
|
||||
[1, 1, 0, 0, 18, 27, 2, 5]
|
||||
]);
|
||||
|
||||
export const flyToSwim = createBodyAnimation('fly-to-swim', 16, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -12],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -8],
|
||||
[1, 1, 6, 0, 8, 10, 6, 5, 0, -2],
|
||||
[1, 1, 7, 0, 8, 10, 6, 5, 0, 4],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, 10],
|
||||
[1, 1, 1, 0, 8, 10, 6, 5, 0, 14]
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -12],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -8],
|
||||
[1, 1, 6, 0, 8, 10, 6, 5, 0, -2],
|
||||
[1, 1, 7, 0, 8, 10, 6, 5, 0, 4],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, 10],
|
||||
[1, 1, 1, 0, 8, 10, 6, 5, 0, 14]
|
||||
]);
|
||||
|
||||
export const flyToSwimBug = createBodyAnimation('fly-to-swim-bug', 16, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -12],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -8],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -2],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, 4],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, 10],
|
||||
[1, 1, 1, 0, 8, 10, 6, 5, 0, 14]
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -12],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -8],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -2],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, 4],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, 10],
|
||||
[1, 1, 1, 0, 8, 10, 6, 5, 0, 14]
|
||||
]);
|
||||
|
||||
export const swimToFly = createBodyAnimation('swim-to-fly', 16, false, [
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, 13],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, 14, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1],
|
||||
[2, 1, 3, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 4, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 5, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[1, 1, 6, 0, 8, 10, 6, 1, 0, 13],
|
||||
[1, 1, 7, 0, 6, 7, 5, 5, 0, -7, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
|
||||
[1, 1, 8, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 9, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 10, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, -17]
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, 13],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, 14, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1],
|
||||
[2, 1, 3, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 4, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 5, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[1, 1, 6, 0, 8, 10, 6, 1, 0, 13],
|
||||
[1, 1, 7, 0, 6, 7, 5, 5, 0, -7, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
|
||||
[1, 1, 8, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 9, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 10, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, -17]
|
||||
]);
|
||||
|
||||
export const swimToFlyBug = createBodyAnimation('swim-to-fly-bug', 16, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, 13],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, 14, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1],
|
||||
[2, 1, 5, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 4, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 5, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[1, 1, 4, 0, 8, 10, 6, 1, 0, 13],
|
||||
[1, 1, 5, 0, 6, 7, 5, 5, 0, -7, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17]
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, 13],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, 14, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1],
|
||||
[2, 1, 5, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 4, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 5, 0, 8, 10, 6, 5, 0, 15, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[1, 1, 4, 0, 8, 10, 6, 1, 0, 13],
|
||||
[1, 1, 5, 0, 6, 7, 5, 5, 0, -7, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17]
|
||||
]);
|
||||
|
||||
//const trotSkew = [-1, 0, 1, 0, -1, -2, -3, -2, -1, 0, 1, 0, -1, -2, -3, -2].map(x => (x + 2) * 0.25);
|
||||
|
||||
export const trot = createBodyAnimation('trot', 24, true, [
|
||||
[1, 1, 0, 0, 2, 10, 2, 10, 0, 1, 0, -1],
|
||||
[1, 1, 0, 0, 3, 11, 3, 11],
|
||||
[1, 1, 0, 0, 4, 12, 4, 12, 0, -1],
|
||||
[1, 1, 0, 0, 5, 13, 5, 13, 0, -2],
|
||||
[1, 1, 0, 0, 6, 14, 6, 14, 0, -2],
|
||||
[1, 1, 0, 0, 7, 15, 7, 15, 0, -2],
|
||||
[1, 1, 0, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 0, 0, 9, 17, 9, 17],
|
||||
[1, 1, 0, 0, 10, 2, 10, 2, 0, 1, 0, -1],
|
||||
[1, 1, 0, 0, 11, 3, 11, 3],
|
||||
[1, 1, 0, 0, 12, 4, 12, 4, 0, -1],
|
||||
[1, 1, 0, 0, 13, 5, 13, 5, 0, -2],
|
||||
[1, 1, 0, 0, 14, 6, 14, 6, 0, -2],
|
||||
[1, 1, 0, 0, 15, 7, 15, 7, 0, -2],
|
||||
[1, 1, 0, 0, 16, 8, 16, 8, 0, -1],
|
||||
[1, 1, 0, 0, 17, 9, 17, 9],
|
||||
[1, 1, 0, 0, 2, 10, 2, 10, 0, 1, 0, -1],
|
||||
[1, 1, 0, 0, 3, 11, 3, 11],
|
||||
[1, 1, 0, 0, 4, 12, 4, 12, 0, -1],
|
||||
[1, 1, 0, 0, 5, 13, 5, 13, 0, -2],
|
||||
[1, 1, 0, 0, 6, 14, 6, 14, 0, -2],
|
||||
[1, 1, 0, 0, 7, 15, 7, 15, 0, -2],
|
||||
[1, 1, 0, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 0, 0, 9, 17, 9, 17],
|
||||
[1, 1, 0, 0, 10, 2, 10, 2, 0, 1, 0, -1],
|
||||
[1, 1, 0, 0, 11, 3, 11, 3],
|
||||
[1, 1, 0, 0, 12, 4, 12, 4, 0, -1],
|
||||
[1, 1, 0, 0, 13, 5, 13, 5, 0, -2],
|
||||
[1, 1, 0, 0, 14, 6, 14, 6, 0, -2],
|
||||
[1, 1, 0, 0, 15, 7, 15, 7, 0, -2],
|
||||
[1, 1, 0, 0, 16, 8, 16, 8, 0, -1],
|
||||
[1, 1, 0, 0, 17, 9, 17, 9],
|
||||
]);
|
||||
|
||||
export const boop = createBodyAnimation('boop', 24, false, [
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
[1, 1, 0, 0, 18, 1, 1, 1],
|
||||
[1, 1, 0, 0, 19, 1, 1, 1],
|
||||
[1, 1, 0, 0, 20, 1, 1, 1],
|
||||
[1, 1, 0, 0, 21, 1, 1, 1],
|
||||
[1, 1, 0, 0, 22, 28, 18, 18, -1],
|
||||
[1, 1, 0, 0, 23, 26, 19, 19, -2, -1],
|
||||
...repeat(5, [1, 1, 0, 0, 23, 27, 20, 20, -3, -1]),
|
||||
[1, 1, 0, 0, 23, 26, 19, 19, -2, -1],
|
||||
[1, 1, 0, 0, 22, 1, 1, 1],
|
||||
[1, 1, 0, 0, 24, 1, 1, 1],
|
||||
[1, 1, 0, 0, 25, 1, 1, 1],
|
||||
[1, 1, 0, 0, 18, 1, 1, 1],
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
[1, 1, 0, 0, 18, 1, 1, 1],
|
||||
[1, 1, 0, 0, 19, 1, 1, 1],
|
||||
[1, 1, 0, 0, 20, 1, 1, 1],
|
||||
[1, 1, 0, 0, 21, 1, 1, 1],
|
||||
[1, 1, 0, 0, 22, 28, 18, 18, -1],
|
||||
[1, 1, 0, 0, 23, 26, 19, 19, -2, -1],
|
||||
...repeat(5, [1, 1, 0, 0, 23, 27, 20, 20, -3, -1]),
|
||||
[1, 1, 0, 0, 23, 26, 19, 19, -2, -1],
|
||||
[1, 1, 0, 0, 22, 1, 1, 1],
|
||||
[1, 1, 0, 0, 24, 1, 1, 1],
|
||||
[1, 1, 0, 0, 25, 1, 1, 1],
|
||||
[1, 1, 0, 0, 18, 1, 1, 1],
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
]);
|
||||
|
||||
export const boopSit = createBodyAnimation('boop-sit', 24, false, [
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[9, 1, 2, 2, 13, 34, 26, 26, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 19, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 20, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 21, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 22, 34, 26, 26, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 23, 34, 26, 26, 0, -1, 0, 0, -1, -1, 0, 1, 0, 1, 0, -1],
|
||||
...repeat(5, [9, 1, 2, 2, 23, 34, 26, 26, -1, -2, 0, 0, -2, -2, 1, 2, 1, 2, 1]),
|
||||
[9, 1, 2, 2, 23, 34, 26, 26, 0, -1, 0, 0, -1, -1, 0, 1, 0, 1, 0, -1],
|
||||
[9, 1, 2, 2, 22, 34, 26, 26, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 24, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 25, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 12, 34, 26, 26, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[9, 1, 2, 2, 13, 34, 26, 26, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 19, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 20, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 21, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 22, 34, 26, 26, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 23, 34, 26, 26, 0, -1, 0, 0, -1, -1, 0, 1, 0, 1, 0, -1],
|
||||
...repeat(5, [9, 1, 2, 2, 23, 34, 26, 26, -1, -2, 0, 0, -2, -2, 1, 2, 1, 2, 1]),
|
||||
[9, 1, 2, 2, 23, 34, 26, 26, 0, -1, 0, 0, -1, -1, 0, 1, 0, 1, 0, -1],
|
||||
[9, 1, 2, 2, 22, 34, 26, 26, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 24, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 25, 34, 26, 26, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 12, 34, 26, 26, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -2],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
], repeat(18, [0, 6]));
|
||||
|
||||
export const boopLie = createBodyAnimation('boop-lie', 24, false, [
|
||||
[15, 1, 0, 2, 38, 38, 26, 26],
|
||||
...repeat(2, [15, 1, 0, 2, 24, 38, 26, 26, 0, 0, 0, 0, 0, 1]),
|
||||
[15, 1, 0, 2, 21, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 22, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 23, 38, 26, 26, 0, 0, -1, -1, 0, 1],
|
||||
[12, 1, 0, 2, 23, 37, 26, 26, -1, 0, 0, 0, -1, 1, 0, 0, 1, 0, 1],
|
||||
...repeat(4, [12, 1, 0, 2, 23, 37, 26, 26, -1, 0, 0, 0, -2, 1, 0, 0, 1, 0, 1]),
|
||||
[15, 1, 0, 2, 23, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 22, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 21, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 38, 38, 26, 26],
|
||||
...repeat(2, [15, 1, 0, 2, 24, 38, 26, 26, 0, 0, 0, 0, 0, 1]),
|
||||
[15, 1, 0, 2, 21, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 22, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 23, 38, 26, 26, 0, 0, -1, -1, 0, 1],
|
||||
[12, 1, 0, 2, 23, 37, 26, 26, -1, 0, 0, 0, -1, 1, 0, 0, 1, 0, 1],
|
||||
...repeat(4, [12, 1, 0, 2, 23, 37, 26, 26, -1, 0, 0, 0, -2, 1, 0, 0, 1, 0, 1]),
|
||||
[15, 1, 0, 2, 23, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 22, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
[15, 1, 0, 2, 21, 38, 26, 26, 0, 0, 0, 0, 0, 1],
|
||||
], repeat(14, [3, 3]));
|
||||
|
||||
export const boopSwim = createBodyAnimation('boop-swim', 24, false, [
|
||||
[1, 1, 0, 0, 1, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 18, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 19, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 20, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 21, 10, 6, 5, 0, 12],
|
||||
[1, 1, 0, 0, 22, 9, 6, 5, -1, 12],
|
||||
[1, 1, 0, 0, 23, 8, 6, 5, -2, 11],
|
||||
...repeat(5, [1, 1, 0, 0, 23, 8, 6, 5, -3, 11]),
|
||||
[1, 1, 0, 0, 23, 9, 6, 5, -2, 11],
|
||||
[1, 1, 0, 0, 22, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 24, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 25, 10, 6, 5, 0, 14],
|
||||
[1, 1, 0, 0, 18, 10, 6, 5, 0, 14],
|
||||
[1, 1, 0, 0, 1, 10, 6, 5, 0, 14]
|
||||
[1, 1, 0, 0, 1, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 18, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 19, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 20, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 21, 10, 6, 5, 0, 12],
|
||||
[1, 1, 0, 0, 22, 9, 6, 5, -1, 12],
|
||||
[1, 1, 0, 0, 23, 8, 6, 5, -2, 11],
|
||||
...repeat(5, [1, 1, 0, 0, 23, 8, 6, 5, -3, 11]),
|
||||
[1, 1, 0, 0, 23, 9, 6, 5, -2, 11],
|
||||
[1, 1, 0, 0, 22, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 24, 10, 6, 5, 0, 13],
|
||||
[1, 1, 0, 0, 25, 10, 6, 5, 0, 14],
|
||||
[1, 1, 0, 0, 18, 10, 6, 5, 0, 14],
|
||||
[1, 1, 0, 0, 1, 10, 6, 5, 0, 14]
|
||||
]);
|
||||
|
||||
export const sit = createBodyAnimation('sit', 24, true, [
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
], [[0, 6]]);
|
||||
|
||||
const sitShadow = [0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 6].map(offset => [0, offset]);
|
||||
|
||||
export const sitDown = createBodyAnimation('sit-down', 24, false, [
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
...repeat(2, [2, 1, 0, 0, 29, 29, 1, 1]),
|
||||
...repeat(2, [3, 1, 0, 0, 30, 30, 21, 21]),
|
||||
[4, 1, 0, 0, 31, 31, 22, 22],
|
||||
[5, 1, 0, 1, 32, 32, 23, 23],
|
||||
[6, 1, 1, 2, 33, 33, 24, 24],
|
||||
[7, 1, 2, 2, 34, 34, 25, 25],
|
||||
[8, 1, 2, 2, 34, 34, 25, 25],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
...repeat(2, [2, 1, 0, 0, 29, 29, 1, 1]),
|
||||
...repeat(2, [3, 1, 0, 0, 30, 30, 21, 21]),
|
||||
[4, 1, 0, 0, 31, 31, 22, 22],
|
||||
[5, 1, 0, 1, 32, 32, 23, 23],
|
||||
[6, 1, 1, 2, 33, 33, 24, 24],
|
||||
[7, 1, 2, 2, 34, 34, 25, 25],
|
||||
[8, 1, 2, 2, 34, 34, 25, 25],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
], sitShadow);
|
||||
|
||||
export const standUp = createBodyAnimation('stand-up', 24, false, [
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[8, 1, 2, 2, 34, 34, 25, 25],
|
||||
[7, 1, 2, 2, 34, 34, 25, 25],
|
||||
[6, 1, 1, 2, 33, 33, 24, 24],
|
||||
[5, 1, 0, 1, 32, 32, 23, 23],
|
||||
[4, 1, 0, 0, 31, 31, 22, 22],
|
||||
...repeat(2, [3, 1, 0, 0, 30, 30, 21, 21]),
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[8, 1, 2, 2, 34, 34, 25, 25],
|
||||
[7, 1, 2, 2, 34, 34, 25, 25],
|
||||
[6, 1, 1, 2, 33, 33, 24, 24],
|
||||
[5, 1, 0, 1, 32, 32, 23, 23],
|
||||
[4, 1, 0, 0, 31, 31, 22, 22],
|
||||
...repeat(2, [3, 1, 0, 0, 30, 30, 21, 21]),
|
||||
[1, 1, 0, 0, 1, 1, 1, 1],
|
||||
], sitShadow.slice(2).reverse());
|
||||
|
||||
export const sitToTrot = createBodyAnimation('sit-to-trot', 24, false, [
|
||||
[7, 1, 2, 2, 34, 35, 24, 25, 0, -1, 0, 0, 0, 2, 1, 1, 0, -1],
|
||||
[6, 1, 1, 2, 27, 36, 23, 24, 0, -2, 0, 0, 0, -2, 0, 0, 0, 1],
|
||||
[5, 1, 0, 1, 5, 13, 5, 23, 0, -2],
|
||||
[4, 1, 0, 0, 6, 14, 6, 5, 0, -2],
|
||||
[3, 1, 0, 0, 7, 15, 7, 15, 0, -2],
|
||||
[2, 1, 0, 0, 8, 16, 8, 16, 0, -1],
|
||||
[7, 1, 2, 2, 34, 35, 24, 25, 0, -1, 0, 0, 0, 2, 1, 1, 0, -1],
|
||||
[6, 1, 1, 2, 27, 36, 23, 24, 0, -2, 0, 0, 0, -2, 0, 0, 0, 1],
|
||||
[5, 1, 0, 1, 5, 13, 5, 23, 0, -2],
|
||||
[4, 1, 0, 0, 6, 14, 6, 5, 0, -2],
|
||||
[3, 1, 0, 0, 7, 15, 7, 15, 0, -2],
|
||||
[2, 1, 0, 0, 8, 16, 8, 16, 0, -1],
|
||||
], [[0, 6], [0, 5], [0, 4], [0, 3], [0, 1], [0, 0]]);
|
||||
|
||||
export const lie = createBodyAnimation('lie', 24, true, [
|
||||
[15, 1, 0, 2, 38, 38, 26, 26],
|
||||
[15, 1, 0, 2, 38, 38, 26, 26],
|
||||
], [[3, 3]]);
|
||||
|
||||
const lieShadow = [[0, 6], [0, 6], [1, 5], [2, 4], [3, 3], [3, 3], [3, 3]];
|
||||
|
||||
export const lieDown = createBodyAnimation('lie-down', 24, false, [
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[10, 1, 2, 2, 35, 34, 26, 26, 0, 0, 0, 0, 0, 0, 0, -1],
|
||||
[11, 1, 1, 2, 36, 36, 26, 26, 0, 0, 0, 0, 0, 0, 1],
|
||||
[12, 1, 1, 2, 37, 37, 26, 26, 0, 0, 0, 0, 0, 0, 1],
|
||||
[13, 1, 0, 2, 38, 38, 26, 26, 0, 0, 0, 0, 0, 0, 1],
|
||||
...repeat(2, [14, 1, 0, 2, 38, 38, 26, 26]),
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
[10, 1, 2, 2, 35, 34, 26, 26, 0, 0, 0, 0, 0, 0, 0, -1],
|
||||
[11, 1, 1, 2, 36, 36, 26, 26, 0, 0, 0, 0, 0, 0, 1],
|
||||
[12, 1, 1, 2, 37, 37, 26, 26, 0, 0, 0, 0, 0, 0, 1],
|
||||
[13, 1, 0, 2, 38, 38, 26, 26, 0, 0, 0, 0, 0, 0, 1],
|
||||
...repeat(2, [14, 1, 0, 2, 38, 38, 26, 26]),
|
||||
], lieShadow);
|
||||
|
||||
export const sitUp = createBodyAnimation('sit-up', 24, false, [
|
||||
...repeat(2, [14, 1, 0, 2, 38, 38, 26, 26]),
|
||||
[13, 1, 0, 2, 38, 38, 26, 26],
|
||||
[12, 1, 1, 2, 37, 37, 26, 26],
|
||||
[11, 1, 1, 2, 36, 36, 26, 26],
|
||||
[10, 1, 2, 2, 35, 34, 26, 26, 0, 0, 0, 0, 0, 0, 0, -1],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
...repeat(2, [14, 1, 0, 2, 38, 38, 26, 26]),
|
||||
[13, 1, 0, 2, 38, 38, 26, 26],
|
||||
[12, 1, 1, 2, 37, 37, 26, 26],
|
||||
[11, 1, 1, 2, 36, 36, 26, 26],
|
||||
[10, 1, 2, 2, 35, 34, 26, 26, 0, 0, 0, 0, 0, 0, 0, -1],
|
||||
[9, 1, 2, 2, 34, 34, 26, 26],
|
||||
], lieShadow.slice().reverse());
|
||||
|
||||
export const lieToTrot = createBodyAnimation('lie-to-trot', 24, false, [
|
||||
[1, 1, 0, 1, 36, 37, 24, 25, 4, 8, 0, 1, 0, 0, 0, 0, 0, 1],
|
||||
[1, 1, 0, 0, 30, 12, 23, 24, 2, 5, 0, 0, 0, -3],
|
||||
[1, 1, 0, 0, 5, 13, 5, 23, 1, 1],
|
||||
[1, 1, 0, 0, 6, 14, 6, 21, 0, 0, 0, -1],
|
||||
[1, 1, 0, 0, 7, 15, 7, 15, 0, -1, 0, -1],
|
||||
[1, 1, 0, 0, 8, 16, 8, 16, 0, -2],
|
||||
[1, 1, 0, 1, 36, 37, 24, 25, 4, 8, 0, 1, 0, 0, 0, 0, 0, 1],
|
||||
[1, 1, 0, 0, 30, 12, 23, 24, 2, 5, 0, 0, 0, -3],
|
||||
[1, 1, 0, 0, 5, 13, 5, 23, 1, 1],
|
||||
[1, 1, 0, 0, 6, 14, 6, 21, 0, 0, 0, -1],
|
||||
[1, 1, 0, 0, 7, 15, 7, 15, 0, -1, 0, -1],
|
||||
[1, 1, 0, 0, 8, 16, 8, 16, 0, -2],
|
||||
], [[2, 1], [1, 0], ...repeat(4, [0, 0])]);
|
||||
|
||||
export const fly = createBodyAnimation('fly', 16, true, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 6, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 7, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 8, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 9, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 10, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 6, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 7, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 8, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 9, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 10, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, -17],
|
||||
]);
|
||||
|
||||
export const boopFly = createBodyAnimation('boop-fly', 16, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 5, 0, 20, 10, 6, 5, 0, -14],
|
||||
[1, 1, 6, 0, 21, 10, 6, 5, 0, -14],
|
||||
[1, 1, 7, 0, 22, 10, 6, 5, -1, -15],
|
||||
[1, 1, 8, 0, 23, 10, 5, 5, -1, -17, -1, 0, -1, -1, 2],
|
||||
[1, 1, 9, 0, 23, 10, 4, 5, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 10, 0, 23, 10, 4, 4, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 11, 0, 23, 10, 4, 3, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 12, 0, 22, 10, 4, 3, 0, -17, -1, 0, 0, 0, 2],
|
||||
[1, 1, 3, 0, 21, 10, 5, 4, 0, -16, 0, 0, 0, 0, 2],
|
||||
[1, 1, 4, 0, 14, 10, 6, 5, 0, -15, 0, 0, 0, 0, 2]
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 5, 0, 20, 10, 6, 5, 0, -14],
|
||||
[1, 1, 6, 0, 21, 10, 6, 5, 0, -14],
|
||||
[1, 1, 7, 0, 22, 10, 6, 5, -1, -15],
|
||||
[1, 1, 8, 0, 23, 10, 5, 5, -1, -17, -1, 0, -1, -1, 2],
|
||||
[1, 1, 9, 0, 23, 10, 4, 5, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 10, 0, 23, 10, 4, 4, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 11, 0, 23, 10, 4, 3, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 12, 0, 22, 10, 4, 3, 0, -17, -1, 0, 0, 0, 2],
|
||||
[1, 1, 3, 0, 21, 10, 5, 4, 0, -16, 0, 0, 0, 0, 2],
|
||||
[1, 1, 4, 0, 14, 10, 6, 5, 0, -15, 0, 0, 0, 0, 2]
|
||||
]);
|
||||
|
||||
export const boopFlyBug = createBodyAnimation('boop-fly-bug', 20, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 5, 0, 20, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 21, 10, 6, 5, 0, -14],
|
||||
[1, 1, 3, 0, 22, 10, 6, 5, -1, -15],
|
||||
[1, 1, 4, 0, 23, 10, 5, 5, -1, -17, -1, 0, -1, -1, 2],
|
||||
[1, 1, 5, 0, 23, 10, 4, 5, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 4, 0, 23, 10, 4, 4, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 3, 0, 23, 10, 4, 3, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 4, 0, 22, 10, 4, 3, 0, -17, -1, 0, 0, 0, 2],
|
||||
[1, 1, 5, 0, 21, 10, 5, 4, 0, -16, 0, 0, 0, 0, 2],
|
||||
[1, 1, 4, 0, 14, 10, 6, 5, 0, -15, 0, 0, 0, 0, 2]
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 5, 0, 20, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 21, 10, 6, 5, 0, -14],
|
||||
[1, 1, 3, 0, 22, 10, 6, 5, -1, -15],
|
||||
[1, 1, 4, 0, 23, 10, 5, 5, -1, -17, -1, 0, -1, -1, 2],
|
||||
[1, 1, 5, 0, 23, 10, 4, 5, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 4, 0, 23, 10, 4, 4, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 3, 0, 23, 10, 4, 3, -1, -18, -1, 0, -1, -1, 2],
|
||||
[1, 1, 4, 0, 22, 10, 4, 3, 0, -17, -1, 0, 0, 0, 2],
|
||||
[1, 1, 5, 0, 21, 10, 5, 4, 0, -16, 0, 0, 0, 0, 2],
|
||||
[1, 1, 4, 0, 14, 10, 6, 5, 0, -15, 0, 0, 0, 0, 2]
|
||||
]);
|
||||
|
||||
export const flyUp = createBodyAnimation('fly-up', 16, false, [
|
||||
[1, 1, 11, 0, 1, 1, 1, 1],
|
||||
[1, 1, 12, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1],
|
||||
[2, 1, 3, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 4, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 5, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[1, 1, 6, 0, 1, 1, 1, 1],
|
||||
[1, 1, 7, 0, 6, 7, 5, 5, 0, -10, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
|
||||
[1, 1, 8, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 9, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 10, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 11, 0, 1, 1, 1, 1],
|
||||
[1, 1, 12, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1],
|
||||
[2, 1, 3, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 4, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 5, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[1, 1, 6, 0, 1, 1, 1, 1],
|
||||
[1, 1, 7, 0, 6, 7, 5, 5, 0, -10, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
|
||||
[1, 1, 8, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 9, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 10, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, -17],
|
||||
]);
|
||||
|
||||
export const trotToFly = createBodyAnimation('trot-to-fly', 20, false, [
|
||||
[1, 1, 11, 0, 6, 14, 6, 14, 0, -2],
|
||||
[1, 1, 12, 0, 7, 15, 7, 15, 0, -2],
|
||||
[1, 1, 3, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 4, 0, 9, 17, 9, 17, 0, 1, 0, 1, 0, 0, 0, -1, 0, -1],
|
||||
[1, 1, 5, 0, 10, 2, 10, 2, 0, 3, 0, 1, 0, 0, 0, -2, 0, -2],
|
||||
[1, 1, 6, 0, 11, 3, 11, 3],
|
||||
[1, 1, 7, 0, 11, 4, 11, 4, 0, -10],
|
||||
[1, 1, 8, 0, 10, 5, 9, 5, 0, -15],
|
||||
[1, 1, 9, 0, 9, 10, 6, 6, 0, -17],
|
||||
[1, 1, 10, 0, 8, 10, 6, 7, 0, -18],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, -17]
|
||||
[1, 1, 11, 0, 6, 14, 6, 14, 0, -2],
|
||||
[1, 1, 12, 0, 7, 15, 7, 15, 0, -2],
|
||||
[1, 1, 3, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 4, 0, 9, 17, 9, 17, 0, 1, 0, 1, 0, 0, 0, -1, 0, -1],
|
||||
[1, 1, 5, 0, 10, 2, 10, 2, 0, 3, 0, 1, 0, 0, 0, -2, 0, -2],
|
||||
[1, 1, 6, 0, 11, 3, 11, 3],
|
||||
[1, 1, 7, 0, 11, 4, 11, 4, 0, -10],
|
||||
[1, 1, 8, 0, 10, 5, 9, 5, 0, -15],
|
||||
[1, 1, 9, 0, 9, 10, 6, 6, 0, -17],
|
||||
[1, 1, 10, 0, 8, 10, 6, 7, 0, -18],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 12, 0, 8, 10, 6, 5, 0, -17]
|
||||
]);
|
||||
|
||||
export const trotToFlyBug = createBodyAnimation('trot-to-fly-bug', 20, false, [
|
||||
[1, 1, 3, 0, 6, 14, 6, 14, 0, -2],
|
||||
[1, 1, 4, 0, 7, 15, 7, 15, 0, -2],
|
||||
[1, 1, 5, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 3, 0, 9, 17, 9, 17, 0, 1, 0, 1, 0, 0, 0, -1, 0, -1],
|
||||
[1, 1, 4, 0, 10, 2, 10, 2, 0, 3, 0, 1, 0, 0, 0, -2, 0, -2],
|
||||
[1, 1, 5, 0, 11, 3, 11, 3],
|
||||
[1, 1, 3, 0, 11, 4, 11, 4, 0, -10],
|
||||
[1, 1, 4, 0, 10, 5, 9, 5, 0, -15],
|
||||
[1, 1, 5, 0, 8, 10, 6, 6, 0, -17],
|
||||
[1, 1, 3, 0, 8, 10, 6, 7, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -17]
|
||||
[1, 1, 3, 0, 6, 14, 6, 14, 0, -2],
|
||||
[1, 1, 4, 0, 7, 15, 7, 15, 0, -2],
|
||||
[1, 1, 5, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 3, 0, 9, 17, 9, 17, 0, 1, 0, 1, 0, 0, 0, -1, 0, -1],
|
||||
[1, 1, 4, 0, 10, 2, 10, 2, 0, 3, 0, 1, 0, 0, 0, -2, 0, -2],
|
||||
[1, 1, 5, 0, 11, 3, 11, 3],
|
||||
[1, 1, 3, 0, 11, 4, 11, 4, 0, -10],
|
||||
[1, 1, 4, 0, 10, 5, 9, 5, 0, -15],
|
||||
[1, 1, 5, 0, 8, 10, 6, 6, 0, -17],
|
||||
[1, 1, 3, 0, 8, 10, 6, 7, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -17]
|
||||
]);
|
||||
|
||||
export const flyToTrot = createBodyAnimation('fly-to-trot', 20, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 10, 0, -16],
|
||||
[1, 1, 4, 0, 8, 11, 5, 11, 0, -15],
|
||||
[1, 1, 5, 0, 8, 12, 4, 12, 0, -12],
|
||||
[1, 1, 6, 0, 7, 13, 5, 13, 0, -8],
|
||||
[1, 1, 6, 0, 7, 14, 6, 14, 0, -6],
|
||||
[1, 1, 6, 0, 7, 15, 7, 15, 0, -4],
|
||||
[1, 1, 7, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 11, 0, 9, 17, 9, 17],
|
||||
[1, 1, 0, 0, 10, 2, 10, 2, 0, 3, 0, -1, 0, 0, 0, -2, 0, -2]
|
||||
[1, 1, 3, 0, 8, 10, 6, 10, 0, -16],
|
||||
[1, 1, 4, 0, 8, 11, 5, 11, 0, -15],
|
||||
[1, 1, 5, 0, 8, 12, 4, 12, 0, -12],
|
||||
[1, 1, 6, 0, 7, 13, 5, 13, 0, -8],
|
||||
[1, 1, 6, 0, 7, 14, 6, 14, 0, -6],
|
||||
[1, 1, 6, 0, 7, 15, 7, 15, 0, -4],
|
||||
[1, 1, 7, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 11, 0, 9, 17, 9, 17],
|
||||
[1, 1, 0, 0, 10, 2, 10, 2, 0, 3, 0, -1, 0, 0, 0, -2, 0, -2]
|
||||
|
||||
// [1, 1, 4, 0, 8, 10, 6, 10, 0, -16],
|
||||
// [1, 1, 5, 0, 8, 10, 6, 10, 0, -18],
|
||||
// [1, 1, 7, 0, 8, 11, 5, 11, 0, -20],
|
||||
// [1, 1, 8, 0, 10, 12, 4, 12, 0, -21],
|
||||
// [1, 1, 9, 0, 11, 13, 4, 13, 0, -20],
|
||||
// [1, 1, 10, 0, 12, 14, 5, 14, 0, -18],
|
||||
// [1, 1, 11, 0, 13, 15, 7, 15, 0, -14, 0, -1],
|
||||
// [1, 1, 4, 0, 14, 16, 8, 16, 0, 0, 0, -1],
|
||||
// [1, 1, 5, 0, 2, 17, 9, 17, 0, 2, 0, 0, 0, -1, 0, -2, 0, -2, 0, -2],
|
||||
// [1, 1, 6, 0, 3, 2, 10, 2, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 2]
|
||||
// [1, 1, 4, 0, 8, 10, 6, 10, 0, -16],
|
||||
// [1, 1, 5, 0, 8, 10, 6, 10, 0, -18],
|
||||
// [1, 1, 7, 0, 8, 11, 5, 11, 0, -20],
|
||||
// [1, 1, 8, 0, 10, 12, 4, 12, 0, -21],
|
||||
// [1, 1, 9, 0, 11, 13, 4, 13, 0, -20],
|
||||
// [1, 1, 10, 0, 12, 14, 5, 14, 0, -18],
|
||||
// [1, 1, 11, 0, 13, 15, 7, 15, 0, -14, 0, -1],
|
||||
// [1, 1, 4, 0, 14, 16, 8, 16, 0, 0, 0, -1],
|
||||
// [1, 1, 5, 0, 2, 17, 9, 17, 0, 2, 0, 0, 0, -1, 0, -2, 0, -2, 0, -2],
|
||||
// [1, 1, 6, 0, 3, 2, 10, 2, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 2]
|
||||
]);
|
||||
|
||||
export const flyToTrotBug = createBodyAnimation('fly-to-trot-bug', 20, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 10, 0, -16],
|
||||
[1, 1, 4, 0, 8, 11, 5, 11, 0, -15],
|
||||
[1, 1, 5, 0, 8, 12, 4, 12, 0, -12],
|
||||
[1, 1, 4, 0, 7, 13, 5, 13, 0, -8],
|
||||
[1, 1, 3, 0, 7, 14, 6, 14, 0, -6],
|
||||
[1, 1, 4, 0, 7, 15, 7, 15, 0, -4],
|
||||
[1, 1, 5, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 4, 0, 9, 17, 9, 17],
|
||||
[1, 1, 3, 0, 10, 2, 10, 2, 0, 3, 0, -1, 0, 0, 0, -2, 0, -2]
|
||||
[1, 1, 3, 0, 8, 10, 6, 10, 0, -16],
|
||||
[1, 1, 4, 0, 8, 11, 5, 11, 0, -15],
|
||||
[1, 1, 5, 0, 8, 12, 4, 12, 0, -12],
|
||||
[1, 1, 4, 0, 7, 13, 5, 13, 0, -8],
|
||||
[1, 1, 3, 0, 7, 14, 6, 14, 0, -6],
|
||||
[1, 1, 4, 0, 7, 15, 7, 15, 0, -4],
|
||||
[1, 1, 5, 0, 8, 16, 8, 16, 0, -1],
|
||||
[1, 1, 4, 0, 9, 17, 9, 17],
|
||||
[1, 1, 3, 0, 10, 2, 10, 2, 0, 3, 0, -1, 0, 0, 0, -2, 0, -2]
|
||||
|
||||
// [1, 1, 4, 0, 8, 10, 6, 10, 0, -16],
|
||||
// [1, 1, 5, 0, 8, 10, 6, 10, 0, -18],
|
||||
// [1, 1, 4, 0, 8, 11, 5, 11, 0, -20],
|
||||
// [1, 1, 3, 0, 10, 12, 4, 12, 0, -21],
|
||||
// [1, 1, 4, 0, 11, 13, 4, 13, 0, -20],
|
||||
// [1, 1, 5, 0, 12, 14, 5, 14, 0, -18],
|
||||
// [1, 1, 4, 0, 13, 15, 7, 15, 0, -14, 0, -1],
|
||||
// [1, 1, 3, 0, 14, 16, 8, 16, 0, 0, 0, -1],
|
||||
// [1, 1, 4, 0, 2, 17, 9, 17, 0, 2, 0, 0, 0, -1, 0, -2, 0, -2, 0, -2],
|
||||
// [1, 1, 5, 0, 3, 2, 10, 2, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 2]
|
||||
// [1, 1, 4, 0, 8, 10, 6, 10, 0, -16],
|
||||
// [1, 1, 5, 0, 8, 10, 6, 10, 0, -18],
|
||||
// [1, 1, 4, 0, 8, 11, 5, 11, 0, -20],
|
||||
// [1, 1, 3, 0, 10, 12, 4, 12, 0, -21],
|
||||
// [1, 1, 4, 0, 11, 13, 4, 13, 0, -20],
|
||||
// [1, 1, 5, 0, 12, 14, 5, 14, 0, -18],
|
||||
// [1, 1, 4, 0, 13, 15, 7, 15, 0, -14, 0, -1],
|
||||
// [1, 1, 3, 0, 14, 16, 8, 16, 0, 0, 0, -1],
|
||||
// [1, 1, 4, 0, 2, 17, 9, 17, 0, 2, 0, 0, 0, -1, 0, -2, 0, -2, 0, -2],
|
||||
// [1, 1, 5, 0, 3, 2, 10, 2, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 2]
|
||||
]);
|
||||
|
||||
export const flyDown = createBodyAnimation('fly-down', 16, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -12],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -10],
|
||||
[1, 1, 6, 0, 8, 10, 6, 5, 0, -8],
|
||||
[1, 1, 7, 0, 8, 10, 6, 5, 0, -6],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -4],
|
||||
[1, 1, 1, 0, 8, 10, 6, 5, 0, -2]
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -12],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -10],
|
||||
[1, 1, 6, 0, 8, 10, 6, 5, 0, -8],
|
||||
[1, 1, 7, 0, 8, 10, 6, 5, 0, -6],
|
||||
[1, 1, 11, 0, 8, 10, 6, 5, 0, -4],
|
||||
[1, 1, 1, 0, 8, 10, 6, 5, 0, -2]
|
||||
]);
|
||||
|
||||
export const flyBug = createBodyAnimation('fly-bug', 24, true, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17]
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -16],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17]
|
||||
]);
|
||||
|
||||
export const flyUpBug = createBodyAnimation('fly-up-bug', 16, false, [
|
||||
[1, 1, 3, 0, 1, 1, 1, 1],
|
||||
[1, 1, 4, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1],
|
||||
[2, 1, 5, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 4, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 5, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[1, 1, 4, 0, 1, 1, 1, 1],
|
||||
[1, 1, 5, 0, 6, 7, 5, 5, 0, -10, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17]
|
||||
[1, 1, 3, 0, 1, 1, 1, 1],
|
||||
[1, 1, 4, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1],
|
||||
[2, 1, 5, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 4, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[2, 1, 5, 0, 29, 29, 21, 21, 0, 2, 0, 2, 0, -2, 0, -2, 2, -2, 2, -2],
|
||||
[1, 1, 4, 0, 1, 1, 1, 1],
|
||||
[1, 1, 5, 0, 6, 7, 5, 5, 0, -10, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -15],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -17],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -18],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -17]
|
||||
]);
|
||||
|
||||
export const flyDownBug = createBodyAnimation('fly-down-bug', 16, false, [
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -12],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -10],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -8],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -6],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -4],
|
||||
[1, 1, 1, 0, 8, 10, 6, 5, 0, -2]
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -14],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -12],
|
||||
[1, 1, 5, 0, 8, 10, 6, 5, 0, -10],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -8],
|
||||
[1, 1, 3, 0, 8, 10, 6, 5, 0, -6],
|
||||
[1, 1, 4, 0, 8, 10, 6, 5, 0, -4],
|
||||
[1, 1, 1, 0, 8, 10, 6, 5, 0, -2]
|
||||
]);
|
||||
|
||||
export const swing = createBodyAnimation('swing', 12, false, [
|
||||
...repeat(1, [1, 1, 0, 0, 1, 1, 1, 1]),
|
||||
...repeat(3, [2, 1, 0, 0, 12, 17, 11, 11, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]),
|
||||
...repeat(1, [1, 1, 0, 0, 1, 1, 1, 1]),
|
||||
...repeat(3, [2, 1, 0, 0, 12, 17, 11, 11, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]),
|
||||
]);
|
||||
|
||||
export const flyAnims = [undefined, fly, fly, fly, flyBug];
|
||||
@@ -464,78 +464,78 @@ export const flyUpAnims = [undefined, flyUp, flyUp, flyUp, flyUpBug];
|
||||
export const flyDownAnims = [undefined, flyDown, flyDown, flyDown, flyDownBug];
|
||||
|
||||
export const animations = [
|
||||
stand, trot, boop, boopSit, boopLie, boopSwim, boopFly, boopFlyBug, sit, sitDown, standUp, lie, lieDown, sitUp,
|
||||
fly, flyBug, flyUp, flyUpBug, flyDown, flyDownBug, sitToTrot, lieToTrot, flyToTrot, flyToTrotBug,
|
||||
swim, trotToSwim, swimToTrot, flyToSwim, swimToFly,
|
||||
stand, trot, boop, boopSit, boopLie, boopSwim, boopFly, boopFlyBug, sit, sitDown, standUp, lie, lieDown, sitUp,
|
||||
fly, flyBug, flyUp, flyUpBug, flyDown, flyDownBug, sitToTrot, lieToTrot, flyToTrot, flyToTrotBug,
|
||||
swim, trotToSwim, swimToTrot, flyToSwim, swimToFly,
|
||||
];
|
||||
|
||||
export const sitDownUp = mergeAnimations('sit', 24, false, [...repeat(12, stand), sitDown, ...repeat(12, sit), standUp]);
|
||||
export const lieDownUp = mergeAnimations('lie', 24, false, [...repeat(12, sit), lieDown, ...repeat(12, lie), sitUp]);
|
||||
|
||||
export function mergeAnimations(name: string, fps: number, loop: boolean, animations: BodyAnimation[]): BodyAnimation {
|
||||
return {
|
||||
name,
|
||||
fps,
|
||||
loop,
|
||||
frames: flatten(animations.map(a => a.frames)),
|
||||
shadow: flatten(animations.map(a => a.shadow || a.frames.map(() => ({ frame: 0, offset: 0 })))),
|
||||
};
|
||||
return {
|
||||
name,
|
||||
fps,
|
||||
loop,
|
||||
frames: flatten(animations.map(a => a.frames)),
|
||||
shadow: flatten(animations.map(a => a.shadow || a.frames.map(() => ({ frame: 0, offset: 0 })))),
|
||||
};
|
||||
}
|
||||
|
||||
// head animations
|
||||
|
||||
export function createHeadFrame([headX = 0, headY = 0, left = 0, right = 0, mouth = 0]: number[]): HeadAnimationFrame {
|
||||
return { headX, headY, left, right, mouth };
|
||||
return { headX, headY, left, right, mouth };
|
||||
}
|
||||
|
||||
export function createHeadAnimation(name: string, fps: number, loop: boolean, frames: number[][]): HeadAnimation {
|
||||
return { name, fps, loop, frames: frames.map(createHeadFrame) };
|
||||
return { name, fps, loop, frames: frames.map(createHeadFrame) };
|
||||
}
|
||||
|
||||
export const smile = createHeadAnimation('smile', 24, true, [
|
||||
[0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 0],
|
||||
]);
|
||||
|
||||
export const nom = createHeadAnimation('nom', 12, true, [
|
||||
[0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 25],
|
||||
[0, 0, 1, 1, 0],
|
||||
[0, 0, 1, 1, 25],
|
||||
]);
|
||||
|
||||
export const laugh = createHeadAnimation('laugh', 8, false, [
|
||||
...repeat(4, [0, 0, 14, 14, 5], [0, 1, 14, 14, 5]),
|
||||
...repeat(4, [0, 0, 14, 14, 5], [0, 1, 14, 14, 5]),
|
||||
]);
|
||||
|
||||
export const yawn = createHeadAnimation('yawn', 12, false, [
|
||||
[0, 0, 3, 3, 8],
|
||||
...repeat(18, [1, -1, 12, 12, 16]),
|
||||
...repeat(8, [0, 0, 12, 12, 12]),
|
||||
[0, 0, 18, 18, 2],
|
||||
[0, 0, 3, 3, 8],
|
||||
...repeat(18, [1, -1, 12, 12, 16]),
|
||||
...repeat(8, [0, 0, 12, 12, 12]),
|
||||
[0, 0, 18, 18, 2],
|
||||
]);
|
||||
|
||||
export const surprise = createHeadAnimation('surprise', 8, false, [
|
||||
[0, 1, 6, 6, 1],
|
||||
...repeat(10, [0, 0, 1, 1, 12]),
|
||||
[0, 1, 6, 6, 1],
|
||||
...repeat(10, [0, 0, 1, 1, 12]),
|
||||
]);
|
||||
|
||||
export const excite = createHeadAnimation('excite', 8, false, [
|
||||
[0, 1, 6, 6, 0],
|
||||
...repeat(10, [0, 0, 1, 1, 5]),
|
||||
[0, 1, 6, 6, 0],
|
||||
...repeat(10, [0, 0, 1, 1, 5]),
|
||||
]);
|
||||
|
||||
export const surpriseSad = createHeadAnimation('surpriseSad', 8, false, [
|
||||
[0, 1, 15, 15, 8],
|
||||
...repeat(8, [0, 0, 15, 15, 8]),
|
||||
[0, 1, 15, 15, 8],
|
||||
...repeat(8, [0, 0, 15, 15, 8]),
|
||||
]);
|
||||
|
||||
export const sneeze = createHeadAnimation('sneeze', 12, false, [
|
||||
[0, 0, 18, 18, 8],
|
||||
...repeat(2, [1, -1, 18, 18, 16]),
|
||||
...repeat(8, [-1, 1, 23, 23, 13]),
|
||||
...repeat(4, [0, 0, 18, 18, 7]),
|
||||
[0, 0, 18, 18, 8],
|
||||
...repeat(2, [1, -1, 18, 18, 16]),
|
||||
...repeat(8, [-1, 1, 23, 23, 13]),
|
||||
...repeat(4, [0, 0, 18, 18, 7]),
|
||||
]);
|
||||
|
||||
export const headAnimations = [
|
||||
smile, nom, laugh, yawn, surprise, surpriseSad, sneeze, excite,
|
||||
smile, nom, laugh, yawn, surprise, surpriseSad, sneeze, excite,
|
||||
];
|
||||
|
||||
// default animations
|
||||
|
||||
+554
-554
File diff suppressed because it is too large
Load Diff
@@ -5,52 +5,52 @@ import { stand } from './ponyAnimations';
|
||||
const defaultBlushColor = blushColor(0);
|
||||
|
||||
export function defaultPonyState(): PonyState {
|
||||
return {
|
||||
animation: stand,
|
||||
animationFrame: 0,
|
||||
headAnimation: undefined,
|
||||
headAnimationFrame: 0,
|
||||
headTurned: false,
|
||||
headTilt: 0,
|
||||
headTurn: 0,
|
||||
blinkFrame: 0,
|
||||
blushColor: defaultBlushColor,
|
||||
holding: undefined,
|
||||
expression: undefined,
|
||||
drawFaceExtra: undefined,
|
||||
flags: PonyStateFlags.None,
|
||||
};
|
||||
return {
|
||||
animation: stand,
|
||||
animationFrame: 0,
|
||||
headAnimation: undefined,
|
||||
headAnimationFrame: 0,
|
||||
headTurned: false,
|
||||
headTilt: 0,
|
||||
headTurn: 0,
|
||||
blinkFrame: 0,
|
||||
blushColor: defaultBlushColor,
|
||||
holding: undefined,
|
||||
expression: undefined,
|
||||
drawFaceExtra: undefined,
|
||||
flags: PonyStateFlags.None,
|
||||
};
|
||||
}
|
||||
|
||||
export function isStateEqual(a: PonyState, b: PonyState) {
|
||||
return a.animation === b.animation &&
|
||||
a.animationFrame === b.animationFrame &&
|
||||
a.headAnimation === b.headAnimation &&
|
||||
a.headAnimationFrame === b.headAnimationFrame &&
|
||||
a.headTurned === b.headTurned &&
|
||||
a.headTilt === b.headTilt &&
|
||||
a.headTurn === b.headTurn &&
|
||||
a.blinkFrame === b.blinkFrame &&
|
||||
a.blushColor === b.blushColor &&
|
||||
a.holding === b.holding &&
|
||||
a.expression === b.expression &&
|
||||
a.drawFaceExtra === b.drawFaceExtra &&
|
||||
a.flags === b.flags;
|
||||
return a.animation === b.animation &&
|
||||
a.animationFrame === b.animationFrame &&
|
||||
a.headAnimation === b.headAnimation &&
|
||||
a.headAnimationFrame === b.headAnimationFrame &&
|
||||
a.headTurned === b.headTurned &&
|
||||
a.headTilt === b.headTilt &&
|
||||
a.headTurn === b.headTurn &&
|
||||
a.blinkFrame === b.blinkFrame &&
|
||||
a.blushColor === b.blushColor &&
|
||||
a.holding === b.holding &&
|
||||
a.expression === b.expression &&
|
||||
a.drawFaceExtra === b.drawFaceExtra &&
|
||||
a.flags === b.flags;
|
||||
}
|
||||
|
||||
export function defaultDrawPonyOptions(): DrawPonyOptions {
|
||||
return {
|
||||
flipped: false,
|
||||
selected: false,
|
||||
shadow: false,
|
||||
extra: false,
|
||||
toy: 0,
|
||||
swimming: false,
|
||||
bounce: false,
|
||||
shadowColor: SHADOW_COLOR,
|
||||
noEars: false,
|
||||
no: NoDraw.None,
|
||||
useAllHooves: false,
|
||||
gameTime: 0,
|
||||
};
|
||||
return {
|
||||
flipped: false,
|
||||
selected: false,
|
||||
shadow: false,
|
||||
extra: false,
|
||||
toy: 0,
|
||||
swimming: false,
|
||||
bounce: false,
|
||||
shadowColor: SHADOW_COLOR,
|
||||
noEars: false,
|
||||
no: NoDraw.None,
|
||||
useAllHooves: false,
|
||||
gameTime: 0,
|
||||
};
|
||||
}
|
||||
|
||||
+25
-25
@@ -1,13 +1,13 @@
|
||||
import { animatorState as state, animatorTransition as transition, anyState, AnimatorState } from '../common/animator';
|
||||
import {
|
||||
stand, sit, sitDown, standUp, lie, lieDown, sitUp, flyBug, fly, flyUp, flyDown, flyUpBug, flyDownBug,
|
||||
trot, boop, boopSit, swim, sitToTrot, lieToTrot, boopLie, trotToFly, trotToFlyBug, boopFly, boopFlyBug,
|
||||
flyToTrot, flyToTrotBug, swing, swimToTrot, trotToSwim, swimToFly, flyToSwim, boopSwim, swimToFlyBug, flyToSwimBug
|
||||
stand, sit, sitDown, standUp, lie, lieDown, sitUp, flyBug, fly, flyUp, flyDown, flyUpBug, flyDownBug,
|
||||
trot, boop, boopSit, swim, sitToTrot, lieToTrot, boopLie, trotToFly, trotToFlyBug, boopFly, boopFlyBug,
|
||||
flyToTrot, flyToTrotBug, swing, swimToTrot, trotToSwim, swimToFly, flyToSwim, boopSwim, swimToFlyBug, flyToSwimBug
|
||||
} from './ponyAnimations';
|
||||
import { BodyAnimation } from '../common/interfaces';
|
||||
|
||||
function n(value: string) {
|
||||
return (DEVELOPMENT || SERVER) ? value : '';
|
||||
return (DEVELOPMENT || SERVER) ? value : '';
|
||||
}
|
||||
|
||||
export const standing = state(n('standing'), stand);
|
||||
@@ -46,12 +46,12 @@ export const flyingToTrotting = state(n('flying-to-trotting'), flyToTrot, { bug:
|
||||
export const swinging = state(n('swinging'), swing);
|
||||
|
||||
export const ponyStates = [
|
||||
anyState, standing, trotting, swimming, swimmingToTrotting, trottingToSwimming,
|
||||
booping, boopingSitting, boopingLying, boopingFlying,
|
||||
sitting, sittingDown, standingUp, sittingToTrotting,
|
||||
lying, lyingDown, sittingUp, lyingToTrotting,
|
||||
hovering, flying, flyingUp, flyingDown, trottingToFlying, flyingToTrotting,
|
||||
swinging, swimmingToFlying, flyingToSwimming, boopingSwimming,
|
||||
anyState, standing, trotting, swimming, swimmingToTrotting, trottingToSwimming,
|
||||
booping, boopingSitting, boopingLying, boopingFlying,
|
||||
sitting, sittingDown, standingUp, sittingToTrotting,
|
||||
lying, lyingDown, sittingUp, lyingToTrotting,
|
||||
hovering, flying, flyingUp, flyingDown, trottingToFlying, flyingToTrotting,
|
||||
swinging, swimmingToFlying, flyingToSwimming, boopingSwimming,
|
||||
];
|
||||
|
||||
transition(hovering, flyingDown, { exitAfter: 0 });
|
||||
@@ -120,36 +120,36 @@ transition(standing, swinging, { exitAfter: 0 });
|
||||
transition(swinging, standing);
|
||||
|
||||
export function isFlyingUp(state: AnimatorState<BodyAnimation> | undefined) {
|
||||
return state === flyingUp || state === trottingToFlying || state === swimmingToFlying;
|
||||
return state === flyingUp || state === trottingToFlying || state === swimmingToFlying;
|
||||
}
|
||||
|
||||
export function isFlyingDown(state: AnimatorState<BodyAnimation> | undefined) {
|
||||
return state === flyingDown || state === flyingToTrotting || state === flyingToSwimming;
|
||||
return state === flyingDown || state === flyingToTrotting || state === flyingToSwimming;
|
||||
}
|
||||
|
||||
export function isSwimmingState(state: AnimatorState<BodyAnimation> | undefined) {
|
||||
return state === swimming || state === trottingToSwimming || state === swimmingToTrotting ||
|
||||
state === flyingToSwimming || state === swimmingToFlying || state === boopingSwimming;
|
||||
return state === swimming || state === trottingToSwimming || state === swimmingToTrotting ||
|
||||
state === flyingToSwimming || state === swimmingToFlying || state === boopingSwimming;
|
||||
}
|
||||
|
||||
export function isFlyingUpOrDown(state: AnimatorState<BodyAnimation> | undefined) {
|
||||
return isFlyingUp(state) || isFlyingDown(state);
|
||||
return isFlyingUp(state) || isFlyingDown(state);
|
||||
}
|
||||
|
||||
export function isSittingDown(state: AnimatorState<BodyAnimation> | undefined) {
|
||||
return state === sittingDown;
|
||||
return state === sittingDown;
|
||||
}
|
||||
export function isSittingUp(state: AnimatorState<BodyAnimation> | undefined) {
|
||||
return state === sittingUp;
|
||||
return state === sittingUp;
|
||||
}
|
||||
|
||||
export function toBoopState(state: AnimatorState<BodyAnimation>) {
|
||||
switch (state) {
|
||||
case standing: return booping;
|
||||
case sitting: return boopingSitting;
|
||||
case lying: return boopingLying;
|
||||
case hovering: return boopingFlying;
|
||||
case swimming: return boopingSwimming;
|
||||
default: return undefined;
|
||||
}
|
||||
switch (state) {
|
||||
case standing: return booping;
|
||||
case sitting: return boopingSitting;
|
||||
case lying: return boopingLying;
|
||||
case hovering: return boopingFlying;
|
||||
case swimming: return boopingSwimming;
|
||||
default: return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
+64
-64
@@ -2,7 +2,7 @@
|
||||
|
||||
import { range, dropRight, compact, max, zip } from 'lodash';
|
||||
import {
|
||||
Eye, Iris, Muzzle, ExpressionExtra, Sprite, ColorExtraSets, PonyInfoBase, SpriteSetBase, ColorExtra, ColorExtraSet
|
||||
Eye, Iris, Muzzle, ExpressionExtra, Sprite, ColorExtraSets, PonyInfoBase, SpriteSetBase, ColorExtra, ColorExtraSet
|
||||
} from '../common/interfaces';
|
||||
import * as sprites from '../generated/sprites';
|
||||
import { HEAD_ACCESSORY_OFFSETS, EXTRA_ACCESSORY_OFFSETS, EAR_ACCESSORY_OFFSETS } from '../common/offsets';
|
||||
@@ -20,14 +20,14 @@ export type Sprites = (Sprite | undefined)[];
|
||||
export type Sets = ColorExtraSets[]; // [frame][type][pattern]
|
||||
|
||||
export const headCenter = [
|
||||
undefined,
|
||||
[[0].map(i => sprites.head[2]![0]![i])],
|
||||
undefined,
|
||||
[[0].map(i => sprites.head[2]![0]![i])],
|
||||
];
|
||||
|
||||
export const claws: Sets = sprites.frontLegHooves
|
||||
.map(f => f && [undefined, undefined, undefined, f[4], undefined, undefined]);
|
||||
.map(f => f && [undefined, undefined, undefined, f[4], undefined, undefined]);
|
||||
export const frontHooves: Sets = sprites.frontLegHooves
|
||||
.map(f => f && [...f.slice(0, 4), ...f.slice(5)]);
|
||||
.map(f => f && [...f.slice(0, 4), ...f.slice(5)]);
|
||||
|
||||
export const frontHoovesInFront = [false, false, true, true, false, false];
|
||||
export const backHoovesInFront = [false, false, true, false, false];
|
||||
@@ -44,77 +44,77 @@ export const neckAccessories = createCompleteSets(sprites.neckAccessories, bodyF
|
||||
export const waistAccessories = createCompleteSets(sprites.waistAccessories, bodyFrames + 1);
|
||||
|
||||
function frameType(sets: Sets, frame: number, type: number) {
|
||||
const set = sets[frame];
|
||||
return set && set[type];
|
||||
const set = sets[frame];
|
||||
return set && set[type];
|
||||
}
|
||||
|
||||
function createCompleteSets(sets: Sets, frameCount: number): Sets {
|
||||
const typeCount = sets.reduce((max, s) => Math.max(max, s ? s.length : 0), 0);
|
||||
const typeRange = range(0, typeCount);
|
||||
const result: Sets = [];
|
||||
const typeCount = sets.reduce((max, s) => Math.max(max, s ? s.length : 0), 0);
|
||||
const typeRange = range(0, typeCount);
|
||||
const result: Sets = [];
|
||||
|
||||
for (let frame = 0; frame < frameCount; frame++) {
|
||||
result.push(typeRange.map(type => frameType(sets, frame, type) || frameType(result, frame - 1, type)));
|
||||
}
|
||||
for (let frame = 0; frame < frameCount; frame++) {
|
||||
result.push(typeRange.map(type => frameType(sets, frame, type) || frameType(result, frame - 1, type)));
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
export function canFly(info: PonyInfoBase<any, SpriteSetBase>) {
|
||||
const type = info.wings && info.wings.type || 0;
|
||||
return type > 0;
|
||||
const type = info.wings && info.wings.type || 0;
|
||||
return type > 0;
|
||||
}
|
||||
|
||||
export function canMagic(info: PonyInfoBase<any, SpriteSetBase>) {
|
||||
const type = info.horn && info.horn.type || 0;
|
||||
return type === 1 || type === 2 || type === 3 || type === 14;
|
||||
const type = info.horn && info.horn.type || 0;
|
||||
return type === 1 || type === 2 || type === 3 || type === 14;
|
||||
}
|
||||
|
||||
export function flipIris(iris: Iris): Iris {
|
||||
if (iris === Iris.Left || iris === Iris.UpLeft) {
|
||||
return iris + 1;
|
||||
} else if (iris === Iris.Right || iris === Iris.UpRight) {
|
||||
return iris - 1;
|
||||
} else {
|
||||
return iris;
|
||||
}
|
||||
if (iris === Iris.Left || iris === Iris.UpLeft) {
|
||||
return iris + 1;
|
||||
} else if (iris === Iris.Right || iris === Iris.UpRight) {
|
||||
return iris - 1;
|
||||
} else {
|
||||
return iris;
|
||||
}
|
||||
}
|
||||
|
||||
export function flipFaceAccessoryType(type: number) {
|
||||
if (type === 6) return 7;
|
||||
if (type === 7) return 6;
|
||||
if (type === 6) return 7;
|
||||
if (type === 7) return 6;
|
||||
|
||||
if (type === 9) return 10;
|
||||
if (type === 10) return 9;
|
||||
if (type === 9) return 10;
|
||||
if (type === 10) return 9;
|
||||
|
||||
return type;
|
||||
return type;
|
||||
}
|
||||
|
||||
export function flipFaceAccessoryPattern(type: number, pattern: number) {
|
||||
if (type === 2) { // dark glasses
|
||||
if (pattern === 1) return 2;
|
||||
if (pattern === 2) return 1;
|
||||
} else if (type === 11) { // large dark glasses
|
||||
if (pattern === 1) return 2;
|
||||
if (pattern === 2) return 1;
|
||||
}
|
||||
if (type === 2) { // dark glasses
|
||||
if (pattern === 1) return 2;
|
||||
if (pattern === 2) return 1;
|
||||
} else if (type === 11) { // large dark glasses
|
||||
if (pattern === 1) return 2;
|
||||
if (pattern === 2) return 1;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
return pattern;
|
||||
}
|
||||
|
||||
export const defaultExpression = {
|
||||
left: Eye.Neutral,
|
||||
leftIris: Iris.Forward,
|
||||
right: Eye.Neutral,
|
||||
rightIris: Iris.Forward,
|
||||
muzzle: Muzzle.Neutral,
|
||||
extra: ExpressionExtra.None,
|
||||
left: Eye.Neutral,
|
||||
leftIris: Iris.Forward,
|
||||
right: Eye.Neutral,
|
||||
rightIris: Iris.Forward,
|
||||
muzzle: Muzzle.Neutral,
|
||||
extra: ExpressionExtra.None,
|
||||
};
|
||||
|
||||
export const blinkFrames: Eye[][] = [];
|
||||
|
||||
function setupBlinkFrames(frames: Eye[]) {
|
||||
dropRight(frames, 1).forEach((f, i) => blinkFrames[f] = blinkFrames[f] || frames.slice(i + 1));
|
||||
dropRight(frames, 1).forEach((f, i) => blinkFrames[f] = blinkFrames[f] || frames.slice(i + 1));
|
||||
}
|
||||
|
||||
setupBlinkFrames([Eye.Neutral, Eye.Neutral2, Eye.Neutral3, Eye.Neutral4, Eye.Neutral5, Eye.Closed]);
|
||||
@@ -125,25 +125,25 @@ setupBlinkFrames([Eye.Angry, Eye.Angry2, Eye.Neutral4, Eye.Neutral5, Eye.Closed]
|
||||
// sets
|
||||
|
||||
function mergeColorExtras(sprites: (ColorExtra | undefined)[]): ColorExtra | undefined {
|
||||
const filtered = compact(sprites);
|
||||
const filtered = compact(sprites);
|
||||
|
||||
return {
|
||||
...filtered[0],
|
||||
colors: max(filtered.map(x => x.colors || 0)),
|
||||
colorMany: filtered.length > 1 ? filtered.map(x => x.color) : undefined,
|
||||
};
|
||||
return {
|
||||
...filtered[0],
|
||||
colors: max(filtered.map(x => x.colors || 0)),
|
||||
colorMany: filtered.length > 1 ? filtered.map(x => x.color) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function mergeSprites(sets: ColorExtraSet[]): ColorExtraSet {
|
||||
return zip(...sets).map(mergeColorExtras);
|
||||
return zip(...sets).map(mergeColorExtras);
|
||||
}
|
||||
|
||||
function mergeSpriteSets(...sets: ColorExtraSets[]): ColorExtraSets {
|
||||
return zip(...sets).map(mergeSprites);
|
||||
return zip(...sets).map(mergeSprites);
|
||||
}
|
||||
|
||||
export const backLegSleeves: Sets = sprites.backLegSleeves
|
||||
.map(sets => sets && [undefined, undefined, undefined, undefined, undefined, ...sets]);
|
||||
.map(sets => sets && [undefined, undefined, undefined, undefined, undefined, ...sets]);
|
||||
|
||||
// TEMP: remove summer hat
|
||||
sprites.headAccessoriesBehind.pop();
|
||||
@@ -157,20 +157,20 @@ export const mergedHeadAccessories = mergeSpriteSets(sprites.headAccessoriesBehi
|
||||
export const mergedFaceAccessories = mergeSpriteSets(sprites.faceAccessories, sprites.faceAccessories2)!;
|
||||
export const mergedChestAccessories = mergeSpriteSets(sprites.chestAccessoriesBehind[1], sprites.chestAccessories[1])!;
|
||||
export const mergedBackAccessories = mergeSpriteSets(
|
||||
backAccessories[1], [undefined, undefined, undefined, undefined, undefined, ...sprites.backLegSleeves[1]!])!;
|
||||
backAccessories[1], [undefined, undefined, undefined, undefined, undefined, ...sprites.backLegSleeves[1]!])!;
|
||||
export const mergedExtraAccessories = mergeSpriteSets(sprites.extraAccessoriesBehind, sprites.extraAccessories)!
|
||||
.slice(0, DEVELOPMENT ? 100 : 2);
|
||||
.slice(0, DEVELOPMENT ? 100 : 2);
|
||||
|
||||
if (DEVELOPMENT) {
|
||||
assertSizes('HEAD_ACCESSORY_OFFSETS', HEAD_ACCESSORY_OFFSETS, mergedManes);
|
||||
assertSizes('EXTRA_ACCESSORY_OFFSETS', EXTRA_ACCESSORY_OFFSETS, mergedManes);
|
||||
assertSizes('EAR_ACCESSORY_OFFSETS', EAR_ACCESSORY_OFFSETS, sprites.ears);
|
||||
assertSizes('frontHoovesInFront', frontHoovesInFront, frontHooves[1]!);
|
||||
assertSizes('backHoovesInFront', backHoovesInFront, sprites.backLegHooves[1]!);
|
||||
assertSizes('HEAD_ACCESSORY_OFFSETS', HEAD_ACCESSORY_OFFSETS, mergedManes);
|
||||
assertSizes('EXTRA_ACCESSORY_OFFSETS', EXTRA_ACCESSORY_OFFSETS, mergedManes);
|
||||
assertSizes('EAR_ACCESSORY_OFFSETS', EAR_ACCESSORY_OFFSETS, sprites.ears);
|
||||
assertSizes('frontHoovesInFront', frontHoovesInFront, frontHooves[1]!);
|
||||
assertSizes('backHoovesInFront', backHoovesInFront, sprites.backLegHooves[1]!);
|
||||
}
|
||||
|
||||
function assertSizes(name: string, a: any[], b: any[]) {
|
||||
if (a.length !== b.length) {
|
||||
throw new Error(`Invalid ${name} length (${a.length} !== ${b.length})`);
|
||||
}
|
||||
if (a.length !== b.length) {
|
||||
throw new Error(`Invalid ${name} length (${a.length} !== ${b.length})`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ import { REV } from '../generated/rev';
|
||||
|
||||
/* istanbul ignore next */
|
||||
export function getUrl(name: string): string {
|
||||
if (DEVELOPMENT)
|
||||
return `/assets/${name}`;
|
||||
if (DEVELOPMENT)
|
||||
return `/assets/${name}`;
|
||||
|
||||
if (!REV[name])
|
||||
throw new Error(`Cannot find file url (${name})`);
|
||||
if (!REV[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`)}`;
|
||||
}
|
||||
|
||||
+20
-20
@@ -9,36 +9,36 @@ let setX = 0;
|
||||
let setY = 0;
|
||||
|
||||
export function setupPlayer(game: PonyTownGame, player: Pony) {
|
||||
const pony = player;
|
||||
pony.flags = setFlag(pony.flags, EntityFlags.Interactive, false);
|
||||
const pony = player;
|
||||
pony.flags = setFlag(pony.flags, EntityFlags.Interactive, false);
|
||||
|
||||
if (isStaticCollision(player, game.map, false)) {
|
||||
fixCollision(player, game.map);
|
||||
}
|
||||
if (isStaticCollision(player, game.map, false)) {
|
||||
fixCollision(player, game.map);
|
||||
}
|
||||
|
||||
game.setPlayer(pony);
|
||||
currentPlayer = player;
|
||||
savePlayerPosition();
|
||||
game.setPlayer(pony);
|
||||
currentPlayer = player;
|
||||
savePlayerPosition();
|
||||
}
|
||||
|
||||
export function savePlayerPosition() {
|
||||
if (currentPlayer) {
|
||||
setX = currentPlayer.x;
|
||||
setY = currentPlayer.y;
|
||||
}
|
||||
if (currentPlayer) {
|
||||
setX = currentPlayer.x;
|
||||
setY = currentPlayer.y;
|
||||
}
|
||||
}
|
||||
|
||||
export function restorePlayerPosition() {
|
||||
if (currentPlayer) {
|
||||
if (currentPlayer.x !== setX || currentPlayer.y !== setY) {
|
||||
currentPlayer.x = setX;
|
||||
currentPlayer.y = setY;
|
||||
DEVELOPMENT && console.warn('Restoring player position');
|
||||
}
|
||||
}
|
||||
if (currentPlayer) {
|
||||
if (currentPlayer.x !== setX || currentPlayer.y !== setY) {
|
||||
currentPlayer.x = setX;
|
||||
currentPlayer.y = setY;
|
||||
DEVELOPMENT && console.warn('Restoring player position');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Account creation lock
|
||||
export const setAclCookie = (acl: string) => {
|
||||
document.cookie = `acl=${acl}; expires=${fromNow(WEEK).toUTCString()}; path=/`;
|
||||
document.cookie = `acl=${acl}; expires=${fromNow(WEEK).toUTCString()}; path=/`;
|
||||
};
|
||||
|
||||
@@ -4,9 +4,9 @@ import { AnimatedRenderable } from '../common/mixins';
|
||||
import { Sprite } from '../common/interfaces';
|
||||
|
||||
export const zzzAnimation1 = createSpriteAnimation(
|
||||
sprites.emote_sleep1, 8, 8, 4, 7, true, sprites.emote_sleep1_flip.frames);
|
||||
sprites.emote_sleep1, 8, 8, 4, 7, true, sprites.emote_sleep1_flip.frames);
|
||||
export const zzzAnimation2 = createSpriteAnimation(
|
||||
sprites.emote_sleep2, 12, 13, 13, 12, true, sprites.emote_sleep2_flip.frames);
|
||||
sprites.emote_sleep2, 12, 13, 13, 12, true, sprites.emote_sleep2_flip.frames);
|
||||
export const zzzAnimations = [zzzAnimation1, zzzAnimation2];
|
||||
|
||||
export const cryAnimation = createSpriteAnimation(sprites.emote_cry2, 12, 0, 13, 0);
|
||||
@@ -24,8 +24,8 @@ export const holdPoofAnimation = createSpriteAnimation(sprites.hold_poof, 12, 0,
|
||||
export const magicAnimation = createSpriteAnimation(sprites.magic2, 8, 2, 6, 0, true);
|
||||
|
||||
function createSpriteAnimation(
|
||||
{ frames, palette }: AnimatedRenderable, fps: number, start: number, middle: number, end: number, loop = true,
|
||||
flipFrames?: Sprite[],
|
||||
{ frames, palette }: AnimatedRenderable, fps: number, start: number, middle: number, end: number, loop = true,
|
||||
flipFrames?: Sprite[],
|
||||
): SpriteAnimation {
|
||||
return { start, middle, end, fps, palette, frames, loop, flipFrames };
|
||||
return { start, middle, end, fps, palette, frames, loop, flipFrames };
|
||||
}
|
||||
|
||||
@@ -6,76 +6,76 @@ import { getUrl } from './rev';
|
||||
import { createFonts } from './fonts';
|
||||
|
||||
export function createSprite(x: number, y: number, w: number, h: number, ox: number, oy: number, type: number): Sprite {
|
||||
return { x, y, w, h, ox, oy, type };
|
||||
return { x, y, w, h, ox, oy, type };
|
||||
}
|
||||
|
||||
export function addTitles(sprites: ColorExtraSets, titles: string[]): ColorExtraSets {
|
||||
return sprites && sprites.map((ns, i) =>
|
||||
ns && ns.map(s => s && { color: s.color, colors: s.colors, title: titles[i], label: titles[i] }));
|
||||
return sprites && sprites.map((ns, i) =>
|
||||
ns && ns.map(s => s && { color: s.color, colors: s.colors, title: titles[i], label: titles[i] }));
|
||||
}
|
||||
|
||||
export function addLabels(sprites: ColorExtraSets, labels: string[]) {
|
||||
sprites && sprites.forEach((s, i) => s && s[0] ? s[0]!.label = labels[i] : undefined);
|
||||
return sprites;
|
||||
sprites && sprites.forEach((s, i) => s && s[0] ? s[0]!.label = labels[i] : undefined);
|
||||
return sprites;
|
||||
}
|
||||
|
||||
export function createEyeSprite(eye: PonyEye | undefined, iris: number, defaultPalette: Uint32Array): ColorExtra | undefined {
|
||||
return eye && { color: eye.irises[iris]!, colors: 2, extra: eye.base, palettes: [defaultPalette] };
|
||||
return eye && { color: eye.irises[iris]!, colors: 2, extra: eye.base, palettes: [defaultPalette] };
|
||||
}
|
||||
|
||||
export function getColorCount(sprite: ColorExtra | undefined): number {
|
||||
return sprite && sprite.colors ? Math.floor((sprite.colors - 1) / 2) : 0;
|
||||
return sprite && sprite.colors ? Math.floor((sprite.colors - 1) / 2) : 0;
|
||||
}
|
||||
|
||||
export function createSpriteUtils() {
|
||||
createFonts();
|
||||
createFonts();
|
||||
}
|
||||
|
||||
type LoadImage = (src: string) => Promise<HTMLImageElement | ImageBitmap>;
|
||||
|
||||
function getImageData(img: HTMLImageElement | ImageBitmap) {
|
||||
const canvas = createCanvas(img.width, img.height);
|
||||
const context = canvas.getContext('2d')!;
|
||||
context.drawImage(img, 0, 0);
|
||||
return context.getImageData(0, 0, img.width, img.height);
|
||||
const canvas = createCanvas(img.width, img.height);
|
||||
const context = canvas.getContext('2d')!;
|
||||
context.drawImage(img, 0, 0);
|
||||
return context.getImageData(0, 0, img.width, img.height);
|
||||
}
|
||||
|
||||
function loadSpriteSheet(sheet: SpriteSheet, loadImage: LoadImage) {
|
||||
return Promise.all([
|
||||
loadImage(sheet.src!),
|
||||
sheet.srcA ? loadImage(sheet.srcA) : Promise.resolve(undefined)
|
||||
])
|
||||
.then(([img, imgA]) => {
|
||||
sheet.data = getImageData(img);
|
||||
return Promise.all([
|
||||
loadImage(sheet.src!),
|
||||
sheet.srcA ? loadImage(sheet.srcA) : Promise.resolve(undefined)
|
||||
])
|
||||
.then(([img, imgA]) => {
|
||||
sheet.data = getImageData(img);
|
||||
|
||||
if (imgA) {
|
||||
const alpha = getImageData(imgA);
|
||||
const alphaData = alpha.data;
|
||||
const sheedData = sheet.data.data;
|
||||
if (imgA) {
|
||||
const alpha = getImageData(imgA);
|
||||
const alphaData = alpha.data;
|
||||
const sheedData = sheet.data.data;
|
||||
|
||||
for (let i = 0; i < sheedData.length; i += 4) {
|
||||
sheedData[i + 3] = alphaData[i];
|
||||
}
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < sheedData.length; i += 4) {
|
||||
sheedData[i + 3] = alphaData[i];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function loadSpriteSheets(sheets: SpriteSheet[], loadImage: LoadImage) {
|
||||
return Promise.all(sheets.map(s => loadSpriteSheet(s, loadImage))).then(noop);
|
||||
return Promise.all(sheets.map(s => loadSpriteSheet(s, loadImage))).then(noop);
|
||||
}
|
||||
|
||||
export let spriteSheetsLoaded = false;
|
||||
|
||||
export function loadAndInitSheets(sheets: SpriteSheet[], loadImage: LoadImage) {
|
||||
return loadSpriteSheets(sheets, loadImage)
|
||||
.then(createSpriteUtils)
|
||||
.then(() => true)
|
||||
.catch(e => (console.error(e), false))
|
||||
.then(loaded => spriteSheetsLoaded = loaded);
|
||||
return loadSpriteSheets(sheets, loadImage)
|
||||
.then(createSpriteUtils)
|
||||
.then(() => true)
|
||||
.catch(e => (console.error(e), false))
|
||||
.then(loaded => spriteSheetsLoaded = loaded);
|
||||
}
|
||||
|
||||
export function loadImageFromUrl(url: string) {
|
||||
return loadImage(getUrl(url));
|
||||
return loadImage(getUrl(url));
|
||||
}
|
||||
|
||||
export const loadAndInitSpriteSheets = once(() => loadAndInitSheets(spriteSheets, loadImageFromUrl));
|
||||
|
||||
+451
-451
File diff suppressed because it is too large
Load Diff
+71
-71
@@ -1,15 +1,15 @@
|
||||
interface TimingEntry {
|
||||
time: number;
|
||||
name?: string;
|
||||
time: number;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface TimingResult {
|
||||
name: string;
|
||||
count: number;
|
||||
selfTime: number;
|
||||
totalTime: number;
|
||||
selfPercent: number;
|
||||
totalPercent: number;
|
||||
name: string;
|
||||
count: number;
|
||||
selfTime: number;
|
||||
totalTime: number;
|
||||
selfPercent: number;
|
||||
totalPercent: number;
|
||||
}
|
||||
|
||||
const ENABLED = false;
|
||||
@@ -19,89 +19,89 @@ const entries: TimingEntry[] = [];
|
||||
let entriesCount = 0;
|
||||
|
||||
if (TIMING && ENABLED) {
|
||||
for (let i = 0; i < ENTRIES_LIMIT; i++) {
|
||||
entries.push({ time: 0, name: undefined });
|
||||
}
|
||||
for (let i = 0; i < ENTRIES_LIMIT; i++) {
|
||||
entries.push({ time: 0, name: undefined });
|
||||
}
|
||||
}
|
||||
|
||||
export function timeStart(name: string) {
|
||||
if (TIMING && ENABLED) {
|
||||
if (entriesCount < ENTRIES_LIMIT) {
|
||||
const entry = entries[entriesCount];
|
||||
entry.time = performance.now();
|
||||
entry.name = name;
|
||||
entriesCount++;
|
||||
} else {
|
||||
console.warn(`exceeded timing entry limit`);
|
||||
}
|
||||
}
|
||||
if (TIMING && ENABLED) {
|
||||
if (entriesCount < ENTRIES_LIMIT) {
|
||||
const entry = entries[entriesCount];
|
||||
entry.time = performance.now();
|
||||
entry.name = name;
|
||||
entriesCount++;
|
||||
} else {
|
||||
console.warn(`exceeded timing entry limit`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function timeEnd() {
|
||||
if (TIMING && ENABLED) {
|
||||
if (entriesCount < ENTRIES_LIMIT) {
|
||||
const entry = entries[entriesCount];
|
||||
entry.time = performance.now();
|
||||
entry.name = undefined;
|
||||
entriesCount++;
|
||||
} else {
|
||||
console.warn(`exceeded timing entry limit`);
|
||||
}
|
||||
}
|
||||
if (TIMING && ENABLED) {
|
||||
if (entriesCount < ENTRIES_LIMIT) {
|
||||
const entry = entries[entriesCount];
|
||||
entry.time = performance.now();
|
||||
entry.name = undefined;
|
||||
entriesCount++;
|
||||
} else {
|
||||
console.warn(`exceeded timing entry limit`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function timeReset() {
|
||||
if (TIMING && ENABLED) {
|
||||
entriesCount = 0;
|
||||
}
|
||||
if (TIMING && ENABLED) {
|
||||
entriesCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function timingCollate(): TimingResult[] {
|
||||
if (TIMING && ENABLED && entriesCount > 0) {
|
||||
interface Entry extends TimingEntry {
|
||||
excludedTime: number;
|
||||
}
|
||||
if (TIMING && ENABLED && entriesCount > 0) {
|
||||
interface Entry extends TimingEntry {
|
||||
excludedTime: number;
|
||||
}
|
||||
|
||||
const listings: TimingResult[] = [];
|
||||
const startStack: Entry[] = [];
|
||||
const listings: TimingResult[] = [];
|
||||
const startStack: Entry[] = [];
|
||||
|
||||
for (let i = 0; i < entriesCount; i++) {
|
||||
const entry = entries[i];
|
||||
for (let i = 0; i < entriesCount; i++) {
|
||||
const entry = entries[i];
|
||||
|
||||
if (entry.name !== undefined) {
|
||||
startStack.push({ ...entry, excludedTime: 0 });
|
||||
} else {
|
||||
const start = startStack.pop()!;
|
||||
const name = start.name!;
|
||||
const time = entry.time - start.time;
|
||||
let listing = listings.find(l => l.name === name);
|
||||
if (entry.name !== undefined) {
|
||||
startStack.push({ ...entry, excludedTime: 0 });
|
||||
} else {
|
||||
const start = startStack.pop()!;
|
||||
const name = start.name!;
|
||||
const time = entry.time - start.time;
|
||||
let listing = listings.find(l => l.name === name);
|
||||
|
||||
if (!listing) {
|
||||
listing = { name, selfTime: 0, totalTime: 0, selfPercent: 0, totalPercent: 0, count: 0 };
|
||||
listings.push(listing);
|
||||
}
|
||||
if (!listing) {
|
||||
listing = { name, selfTime: 0, totalTime: 0, selfPercent: 0, totalPercent: 0, count: 0 };
|
||||
listings.push(listing);
|
||||
}
|
||||
|
||||
listing.count++;
|
||||
listing.selfTime += (time - start.excludedTime);
|
||||
listing.totalTime += time;
|
||||
listing.count++;
|
||||
listing.selfTime += (time - start.excludedTime);
|
||||
listing.totalTime += time;
|
||||
|
||||
if (startStack.length) {
|
||||
startStack[startStack.length - 1].excludedTime += time;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (startStack.length) {
|
||||
startStack[startStack.length - 1].excludedTime += time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const firstTime = entries[0].time;
|
||||
const lastTime = entries[entriesCount - 1].time;
|
||||
const totalTime = lastTime - firstTime;
|
||||
const firstTime = entries[0].time;
|
||||
const lastTime = entries[entriesCount - 1].time;
|
||||
const totalTime = lastTime - firstTime;
|
||||
|
||||
for (const listing of listings) {
|
||||
listing.selfPercent = 100 * listing.selfTime / totalTime;
|
||||
listing.totalPercent = 100 * listing.totalTime / totalTime;
|
||||
}
|
||||
for (const listing of listings) {
|
||||
listing.selfPercent = 100 * listing.selfTime / totalTime;
|
||||
listing.totalPercent = 100 * listing.totalTime / totalTime;
|
||||
}
|
||||
|
||||
return listings.sort((a, b) => b.selfTime - a.selfTime);
|
||||
}
|
||||
return listings.sort((a, b) => b.selfTime - a.selfTime);
|
||||
}
|
||||
|
||||
return [];
|
||||
return [];
|
||||
}
|
||||
|
||||
+86
-86
@@ -11,17 +11,17 @@ import { SpriteBatch } from '../graphics/spriteBatch';
|
||||
import { BATCH_SIZE_MAX } from '../common/constants';
|
||||
|
||||
export interface WebGL {
|
||||
gl: WebGLRenderingContext;
|
||||
frameBuffer: FrameBuffer | undefined;
|
||||
frameBufferSheet: SpriteSheet;
|
||||
spriteShader: Shader;
|
||||
lightShader: Shader;
|
||||
paletteShader: Shader;
|
||||
spriteBatch: SpriteBatch;
|
||||
paletteBatch: PaletteSpriteBatch;
|
||||
palettes: CommonPalettes;
|
||||
failedFBO: boolean;
|
||||
renderer: string;
|
||||
gl: WebGLRenderingContext;
|
||||
frameBuffer: FrameBuffer | undefined;
|
||||
frameBufferSheet: SpriteSheet;
|
||||
spriteShader: Shader;
|
||||
lightShader: Shader;
|
||||
paletteShader: Shader;
|
||||
spriteBatch: SpriteBatch;
|
||||
paletteBatch: PaletteSpriteBatch;
|
||||
palettes: CommonPalettes;
|
||||
failedFBO: boolean;
|
||||
renderer: string;
|
||||
}
|
||||
|
||||
const spriteShaderSource = spriteShader;
|
||||
@@ -29,108 +29,108 @@ const paletteShaderSource = paletteLayersShader;
|
||||
const lightShaderSource = lightShader;
|
||||
|
||||
function createIndices(capacity: number) {
|
||||
const numIndices = (capacity * 6) | 0;
|
||||
const indices = new Uint16Array(numIndices);
|
||||
const numIndices = (capacity * 6) | 0;
|
||||
const indices = new Uint16Array(numIndices);
|
||||
|
||||
for (let i = 0, j = 0; i < numIndices; j = (j + 4) | 0) {
|
||||
indices[i++] = (j + 0) | 0;
|
||||
indices[i++] = (j + 1) | 0;
|
||||
indices[i++] = (j + 2) | 0;
|
||||
indices[i++] = (j + 0) | 0;
|
||||
indices[i++] = (j + 2) | 0;
|
||||
indices[i++] = (j + 3) | 0;
|
||||
}
|
||||
for (let i = 0, j = 0; i < numIndices; j = (j + 4) | 0) {
|
||||
indices[i++] = (j + 0) | 0;
|
||||
indices[i++] = (j + 1) | 0;
|
||||
indices[i++] = (j + 2) | 0;
|
||||
indices[i++] = (j + 0) | 0;
|
||||
indices[i++] = (j + 2) | 0;
|
||||
indices[i++] = (j + 3) | 0;
|
||||
}
|
||||
|
||||
return indices;
|
||||
return indices;
|
||||
}
|
||||
|
||||
export function initWebGL(canvas: HTMLCanvasElement, paletteManager: PaletteManager, camera: Camera): WebGL {
|
||||
const gl = getWebGLContext(canvas);
|
||||
return initWebGLResources(gl, paletteManager, camera);
|
||||
const gl = getWebGLContext(canvas);
|
||||
return initWebGLResources(gl, paletteManager, camera);
|
||||
}
|
||||
|
||||
export function initWebGLResources(gl: WebGLRenderingContext, paletteManager: PaletteManager, camera: Camera): WebGL {
|
||||
let renderer = '';
|
||||
let failedFBO = false;
|
||||
let frameBuffer: FrameBuffer | undefined;
|
||||
let frameBufferSheet: SpriteSheet = { texture: undefined, sprites: [], palette: false };
|
||||
let renderer = '';
|
||||
let failedFBO = false;
|
||||
let frameBuffer: FrameBuffer | undefined;
|
||||
let frameBufferSheet: SpriteSheet = { texture: undefined, sprites: [], palette: false };
|
||||
|
||||
try {
|
||||
const size = getRenderTargetSize(camera.w, camera.h);
|
||||
frameBuffer = createFrameBuffer(gl, size, size);
|
||||
frameBufferSheet.texture = frameBuffer.texture;
|
||||
} catch (e) {
|
||||
DEVELOPMENT && console.warn(e);
|
||||
failedFBO = true;
|
||||
}
|
||||
try {
|
||||
const size = getRenderTargetSize(camera.w, camera.h);
|
||||
frameBuffer = createFrameBuffer(gl, size, size);
|
||||
frameBufferSheet.texture = frameBuffer.texture;
|
||||
} catch (e) {
|
||||
DEVELOPMENT && console.warn(e);
|
||||
failedFBO = true;
|
||||
}
|
||||
|
||||
createTexturesForSpriteSheets(gl, sprites.spriteSheets);
|
||||
const palettes = createCommonPalettes(paletteManager);
|
||||
createTexturesForSpriteSheets(gl, sprites.spriteSheets);
|
||||
const palettes = createCommonPalettes(paletteManager);
|
||||
|
||||
const paletteShader = createShader(gl, paletteShaderSource);
|
||||
const spriteShader = createShader(gl, spriteShaderSource);
|
||||
const lightShader = createShader(gl, lightShaderSource);
|
||||
const paletteShader = createShader(gl, paletteShaderSource);
|
||||
const spriteShader = createShader(gl, spriteShaderSource);
|
||||
const lightShader = createShader(gl, lightShaderSource);
|
||||
|
||||
const VERTICES_PER_SPRITE = 4;
|
||||
const buffer = new ArrayBuffer(BATCH_SIZE_MAX * VERTICES_PER_SPRITE * PALETTE_BATCH_BYTES_PER_VERTEX);
|
||||
const vertexBuffer = gl.createBuffer();
|
||||
const VERTICES_PER_SPRITE = 4;
|
||||
const buffer = new ArrayBuffer(BATCH_SIZE_MAX * VERTICES_PER_SPRITE * PALETTE_BATCH_BYTES_PER_VERTEX);
|
||||
const vertexBuffer = gl.createBuffer();
|
||||
|
||||
if (!vertexBuffer) {
|
||||
throw new Error(`Failed to allocate vertex buffer`);
|
||||
}
|
||||
if (!vertexBuffer) {
|
||||
throw new Error(`Failed to allocate vertex buffer`);
|
||||
}
|
||||
|
||||
const indexBuffer = gl.createBuffer();
|
||||
const indexBuffer = gl.createBuffer();
|
||||
|
||||
if (!indexBuffer) {
|
||||
throw new Error(`Failed to allocate index buffer`);
|
||||
}
|
||||
if (!indexBuffer) {
|
||||
throw new Error(`Failed to allocate index buffer`);
|
||||
}
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, createIndices(BATCH_SIZE_MAX), gl.STATIC_DRAW);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, createIndices(BATCH_SIZE_MAX), gl.STATIC_DRAW);
|
||||
|
||||
const vertexBuffer2 = gl.createBuffer();
|
||||
const vertexBuffer2 = gl.createBuffer();
|
||||
|
||||
if (!vertexBuffer2) {
|
||||
throw new Error(`Failed to allocate vertex buffer (2)`);
|
||||
}
|
||||
if (!vertexBuffer2) {
|
||||
throw new Error(`Failed to allocate vertex buffer (2)`);
|
||||
}
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer2);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer2);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW);
|
||||
|
||||
const spriteBatch = new SpriteBatch(gl, BATCH_SIZE_MAX, buffer, vertexBuffer2, indexBuffer);
|
||||
const paletteBatch = new PaletteSpriteBatch(gl, BATCH_SIZE_MAX, buffer, vertexBuffer, indexBuffer);
|
||||
spriteBatch.rectSprite = sprites.pixel;
|
||||
paletteBatch.rectSprite = sprites.pixel2;
|
||||
paletteBatch.defaultPalette = palettes.defaultPalette;
|
||||
const spriteBatch = new SpriteBatch(gl, BATCH_SIZE_MAX, buffer, vertexBuffer2, indexBuffer);
|
||||
const paletteBatch = new PaletteSpriteBatch(gl, BATCH_SIZE_MAX, buffer, vertexBuffer, indexBuffer);
|
||||
spriteBatch.rectSprite = sprites.pixel;
|
||||
paletteBatch.rectSprite = sprites.pixel2;
|
||||
paletteBatch.defaultPalette = palettes.defaultPalette;
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
||||
|
||||
paletteManager.init(gl);
|
||||
paletteManager.init(gl);
|
||||
|
||||
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
||||
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
||||
|
||||
if (debugInfo) {
|
||||
renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
|
||||
}
|
||||
if (debugInfo) {
|
||||
renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
|
||||
}
|
||||
|
||||
return {
|
||||
gl, paletteShader, spriteShader, lightShader, spriteBatch, paletteBatch,
|
||||
frameBuffer, frameBufferSheet, palettes, failedFBO, renderer,
|
||||
};
|
||||
return {
|
||||
gl, paletteShader, spriteShader, lightShader, spriteBatch, paletteBatch,
|
||||
frameBuffer, frameBufferSheet, palettes, failedFBO, renderer,
|
||||
};
|
||||
}
|
||||
|
||||
export function disposeWebGL(webgl: WebGL) {
|
||||
const { gl } = webgl;
|
||||
const { gl } = webgl;
|
||||
|
||||
unbindAllTexturesAndBuffers(gl);
|
||||
disposeTexturesForSpriteSheets(gl, sprites.spriteSheets);
|
||||
disposeFrameBuffer(gl, webgl.frameBuffer);
|
||||
disposeShader(gl, webgl.lightShader);
|
||||
disposeShader(gl, webgl.spriteShader);
|
||||
disposeShader(gl, webgl.paletteShader);
|
||||
webgl.spriteBatch.dispose();
|
||||
webgl.paletteBatch.dispose();
|
||||
unbindAllTexturesAndBuffers(gl);
|
||||
disposeTexturesForSpriteSheets(gl, sprites.spriteSheets);
|
||||
disposeFrameBuffer(gl, webgl.frameBuffer);
|
||||
disposeShader(gl, webgl.lightShader);
|
||||
disposeShader(gl, webgl.spriteShader);
|
||||
disposeShader(gl, webgl.paletteShader);
|
||||
webgl.spriteBatch.dispose();
|
||||
webgl.paletteBatch.dispose();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user