mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-24 21:55:52 +02:00
tslint changes
This commit is contained in:
@@ -4,73 +4,73 @@ import { Sprite, PonyInfo } from '../../../../common/interfaces';
|
||||
let openedPopover: ToolsFrame;
|
||||
|
||||
@Component({
|
||||
selector: 'tools-frame',
|
||||
templateUrl: 'tools-frame.pug',
|
||||
styleUrls: ['tools-frame.scss'],
|
||||
selector: 'tools-frame',
|
||||
templateUrl: 'tools-frame.pug',
|
||||
styleUrls: ['tools-frame.scss'],
|
||||
})
|
||||
export class ToolsFrame {
|
||||
@Input() x = 0;
|
||||
@Input() y = 0;
|
||||
@Input() sprites!: Sprite[];
|
||||
@Input() frame!: number;
|
||||
@Input() pony!: PonyInfo;
|
||||
@Input() reverseExtra = false;
|
||||
@Input() circle?: string;
|
||||
@Output() frameChange = new EventEmitter<number>();
|
||||
popoverIsOpen = false;
|
||||
placement = 'right';
|
||||
private savedFrame = 0;
|
||||
private selected = false;
|
||||
constructor(private element: ElementRef) {
|
||||
}
|
||||
get sprite() {
|
||||
return this.sprites[this.frame];
|
||||
}
|
||||
closePopover = () => {
|
||||
if (this.popoverIsOpen) {
|
||||
this.togglePopover();
|
||||
}
|
||||
}
|
||||
togglePopover() {
|
||||
const rect = (this.element.nativeElement as HTMLElement).getBoundingClientRect();
|
||||
this.placement = (rect.left < (window.innerWidth / 2)) ? 'right' : 'left';
|
||||
@Input() x = 0;
|
||||
@Input() y = 0;
|
||||
@Input() sprites!: Sprite[];
|
||||
@Input() frame!: number;
|
||||
@Input() pony!: PonyInfo;
|
||||
@Input() reverseExtra = false;
|
||||
@Input() circle?: string;
|
||||
@Output() frameChange = new EventEmitter<number>();
|
||||
popoverIsOpen = false;
|
||||
placement = 'right';
|
||||
private savedFrame = 0;
|
||||
private selected = false;
|
||||
constructor(private element: ElementRef) {
|
||||
}
|
||||
get sprite() {
|
||||
return this.sprites[this.frame];
|
||||
}
|
||||
closePopover = () => {
|
||||
if (this.popoverIsOpen) {
|
||||
this.togglePopover();
|
||||
}
|
||||
}
|
||||
togglePopover() {
|
||||
const rect = (this.element.nativeElement as HTMLElement).getBoundingClientRect();
|
||||
this.placement = (rect.left < (window.innerWidth / 2)) ? 'right' : 'left';
|
||||
|
||||
if (!this.popoverIsOpen) {
|
||||
if (openedPopover) {
|
||||
openedPopover.popoverIsOpen = false;
|
||||
}
|
||||
if (!this.popoverIsOpen) {
|
||||
if (openedPopover) {
|
||||
openedPopover.popoverIsOpen = false;
|
||||
}
|
||||
|
||||
openedPopover = this;
|
||||
}
|
||||
openedPopover = this;
|
||||
}
|
||||
|
||||
this.popoverIsOpen = !this.popoverIsOpen;
|
||||
this.popoverIsOpen = !this.popoverIsOpen;
|
||||
|
||||
if (this.popoverIsOpen) {
|
||||
this.selected = false;
|
||||
window.addEventListener('mousedown', this.closePopover);
|
||||
} else {
|
||||
window.removeEventListener('mousedown', this.closePopover);
|
||||
}
|
||||
if (this.popoverIsOpen) {
|
||||
this.selected = false;
|
||||
window.addEventListener('mousedown', this.closePopover);
|
||||
} else {
|
||||
window.removeEventListener('mousedown', this.closePopover);
|
||||
}
|
||||
|
||||
setTimeout(() => { }, 10);
|
||||
}
|
||||
select(index: number) {
|
||||
this.selected = true;
|
||||
this.frame = index;
|
||||
this.togglePopover();
|
||||
this.frameChange.emit(this.frame);
|
||||
}
|
||||
enter(index: number) {
|
||||
if (!this.selected) {
|
||||
this.savedFrame = this.frame;
|
||||
this.frame = index;
|
||||
this.frameChange.emit(this.frame);
|
||||
}
|
||||
}
|
||||
leave() {
|
||||
if (!this.selected) {
|
||||
this.frame = this.savedFrame;
|
||||
this.frameChange.emit(this.frame);
|
||||
}
|
||||
}
|
||||
setTimeout(() => { }, 10);
|
||||
}
|
||||
select(index: number) {
|
||||
this.selected = true;
|
||||
this.frame = index;
|
||||
this.togglePopover();
|
||||
this.frameChange.emit(this.frame);
|
||||
}
|
||||
enter(index: number) {
|
||||
if (!this.selected) {
|
||||
this.savedFrame = this.frame;
|
||||
this.frame = index;
|
||||
this.frameChange.emit(this.frame);
|
||||
}
|
||||
}
|
||||
leave() {
|
||||
if (!this.selected) {
|
||||
this.frame = this.savedFrame;
|
||||
this.frameChange.emit(this.frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,27 +3,27 @@ import { Point } from '../../../../common/interfaces';
|
||||
import { faChevronRight, faChevronLeft, faChevronDown, faChevronUp } from '../../../../client/icons';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-offset',
|
||||
templateUrl: 'tools-offset.pug',
|
||||
styleUrls: ['tools-offset.scss'],
|
||||
selector: 'tools-offset',
|
||||
templateUrl: 'tools-offset.pug',
|
||||
styleUrls: ['tools-offset.scss'],
|
||||
})
|
||||
export class ToolsOffset {
|
||||
readonly rightIcon = faChevronRight;
|
||||
readonly leftIcon = faChevronLeft;
|
||||
readonly upIcon = faChevronUp;
|
||||
readonly downIcon = faChevronDown;
|
||||
@Input() offset?: Point;
|
||||
@Output() change = new EventEmitter<void>();
|
||||
moveX(value: number) {
|
||||
if (this.offset) {
|
||||
this.offset.x += value;
|
||||
this.change.emit();
|
||||
}
|
||||
}
|
||||
moveY(value: number) {
|
||||
if (this.offset) {
|
||||
this.offset.y += value;
|
||||
this.change.emit();
|
||||
}
|
||||
}
|
||||
readonly rightIcon = faChevronRight;
|
||||
readonly leftIcon = faChevronLeft;
|
||||
readonly upIcon = faChevronUp;
|
||||
readonly downIcon = faChevronDown;
|
||||
@Input() offset?: Point;
|
||||
@Output() change = new EventEmitter<void>();
|
||||
moveX(value: number) {
|
||||
if (this.offset) {
|
||||
this.offset.x += value;
|
||||
this.change.emit();
|
||||
}
|
||||
}
|
||||
moveY(value: number) {
|
||||
if (this.offset) {
|
||||
this.offset.y += value;
|
||||
this.change.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,53 +3,53 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { faChevronRight, faChevronLeft, faChevronUp, faChevronDown } from '../../../../client/icons';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-range',
|
||||
templateUrl: 'tools-range.pug',
|
||||
styleUrls: ['tools-range.scss'],
|
||||
providers: [
|
||||
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ToolsRange), multi: true },
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
selector: 'tools-range',
|
||||
templateUrl: 'tools-range.pug',
|
||||
styleUrls: ['tools-range.scss'],
|
||||
providers: [
|
||||
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ToolsRange), multi: true },
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ToolsRange implements ControlValueAccessor {
|
||||
readonly rightIcon = faChevronRight;
|
||||
readonly leftIcon = faChevronLeft;
|
||||
readonly upIcon = faChevronUp;
|
||||
readonly downIcon = faChevronDown;
|
||||
@Input() min = 0;
|
||||
@Input() max = 100;
|
||||
@Input() vertical = false;
|
||||
@Input() small = false;
|
||||
@Input() placeholder?: string;
|
||||
@Output() change = new EventEmitter<number>();
|
||||
private _value = 0;
|
||||
private propagateChange: any = () => { };
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
set value(value: number) {
|
||||
this._value = value;
|
||||
this.propagateChange(value);
|
||||
this.change.emit();
|
||||
}
|
||||
decrement() {
|
||||
if (this.value > this.min) {
|
||||
this.value = this.value - 1;
|
||||
}
|
||||
}
|
||||
increment() {
|
||||
if (this.value < this.max) {
|
||||
this.value = this.value + 1;
|
||||
}
|
||||
}
|
||||
writeValue(value: number | undefined) {
|
||||
if (value !== undefined) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
registerOnChange(callback: any) {
|
||||
this.propagateChange = callback;
|
||||
}
|
||||
registerOnTouched() {
|
||||
}
|
||||
readonly rightIcon = faChevronRight;
|
||||
readonly leftIcon = faChevronLeft;
|
||||
readonly upIcon = faChevronUp;
|
||||
readonly downIcon = faChevronDown;
|
||||
@Input() min = 0;
|
||||
@Input() max = 100;
|
||||
@Input() vertical = false;
|
||||
@Input() small = false;
|
||||
@Input() placeholder?: string;
|
||||
@Output() change = new EventEmitter<number>();
|
||||
private _value = 0;
|
||||
private propagateChange: any = () => { };
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
set value(value: number) {
|
||||
this._value = value;
|
||||
this.propagateChange(value);
|
||||
this.change.emit();
|
||||
}
|
||||
decrement() {
|
||||
if (this.value > this.min) {
|
||||
this.value = this.value - 1;
|
||||
}
|
||||
}
|
||||
increment() {
|
||||
if (this.value < this.max) {
|
||||
this.value = this.value + 1;
|
||||
}
|
||||
}
|
||||
writeValue(value: number | undefined) {
|
||||
if (value !== undefined) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
registerOnChange(callback: any) {
|
||||
this.propagateChange = callback;
|
||||
}
|
||||
registerOnTouched() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,31 +2,31 @@ import { Component, Input, ChangeDetectionStrategy, EventEmitter, Output } from
|
||||
import { faChevronRight, faChevronLeft, faChevronUp, faChevronDown } from '../../../../client/icons';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-xy',
|
||||
templateUrl: 'tools-xy.pug',
|
||||
styleUrls: ['tools-xy.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
selector: 'tools-xy',
|
||||
templateUrl: 'tools-xy.pug',
|
||||
styleUrls: ['tools-xy.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ToolsXY {
|
||||
readonly rightIcon = faChevronRight;
|
||||
readonly leftIcon = faChevronLeft;
|
||||
readonly upIcon = faChevronUp;
|
||||
readonly downIcon = faChevronDown;
|
||||
@Input() min = 0;
|
||||
@Input() max = 100;
|
||||
@Input() x = 0;
|
||||
@Input() y = 0;
|
||||
@Output() xChange = new EventEmitter<number>();
|
||||
@Output() yChange = new EventEmitter<number>();
|
||||
@Output() change = new EventEmitter<void>();
|
||||
changeX(value: number) {
|
||||
this.x = value;
|
||||
this.xChange.emit(value);
|
||||
this.change.emit();
|
||||
}
|
||||
changeY(value: number) {
|
||||
this.y = value;
|
||||
this.yChange.emit(value);
|
||||
this.change.emit();
|
||||
}
|
||||
readonly rightIcon = faChevronRight;
|
||||
readonly leftIcon = faChevronLeft;
|
||||
readonly upIcon = faChevronUp;
|
||||
readonly downIcon = faChevronDown;
|
||||
@Input() min = 0;
|
||||
@Input() max = 100;
|
||||
@Input() x = 0;
|
||||
@Input() y = 0;
|
||||
@Output() xChange = new EventEmitter<number>();
|
||||
@Output() yChange = new EventEmitter<number>();
|
||||
@Output() change = new EventEmitter<void>();
|
||||
changeX(value: number) {
|
||||
this.x = value;
|
||||
this.xChange.emit(value);
|
||||
this.change.emit();
|
||||
}
|
||||
changeY(value: number) {
|
||||
this.y = value;
|
||||
this.yChange.emit(value);
|
||||
this.change.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,336 +23,336 @@ const patternColors = [RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, BLACK];
|
||||
const whiteColors = [WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE];
|
||||
|
||||
function maxPatterns(sprites: Sets): number {
|
||||
return max(sprites.map(s => s && s.length ? max(s.map(x => x ? x.length : 0)) : 0))!;
|
||||
return max(sprites.map(s => s && s.length ? max(s.map(x => x ? x.length : 0)) : 0))!;
|
||||
}
|
||||
|
||||
const backupSprites: any = {
|
||||
head: [
|
||||
undefined,
|
||||
[
|
||||
[
|
||||
{}
|
||||
],
|
||||
],
|
||||
],
|
||||
head: [
|
||||
undefined,
|
||||
[
|
||||
[
|
||||
{}
|
||||
],
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
function getSets(sheet: Sheet, key: string, override?: string): Sets | undefined {
|
||||
const setsKey = override || key || '';
|
||||
const sets = backupSprites[setsKey] || (sprites as any)[setsKey];
|
||||
const setsKey = override || key || '';
|
||||
const sets = backupSprites[setsKey] || (sprites as any)[setsKey];
|
||||
|
||||
if (sheet.duplicateFirstFrame !== undefined) {
|
||||
return times(sheet.duplicateFirstFrame, () => sets[0]);
|
||||
} else {
|
||||
return sheet.single ? [sets] : sets;
|
||||
}
|
||||
if (sheet.duplicateFirstFrame !== undefined) {
|
||||
return times(sheet.duplicateFirstFrame, () => sets[0]);
|
||||
} else {
|
||||
return sheet.single ? [sets] : sets;
|
||||
}
|
||||
}
|
||||
|
||||
function getSetsForFirstKey(sheet: Sheet) {
|
||||
const layer = sheet.layers.find(l => !!l.set);
|
||||
return layer && getSets(sheet, layer.set!);
|
||||
const layer = sheet.layers.find(l => !!l.set);
|
||||
return layer && getSets(sheet, layer.set!);
|
||||
}
|
||||
|
||||
export function getCols(sheet: Sheet) {
|
||||
return sheet.state!.animation.frames.length;
|
||||
return sheet.state!.animation.frames.length;
|
||||
}
|
||||
|
||||
export function getRows(sheet: Sheet) {
|
||||
if (sheet.rows !== undefined) {
|
||||
return sheet.rows;
|
||||
} else {
|
||||
const sets = getSetsForFirstKey(sheet);
|
||||
const maxFrames = sets && max(sets.map(f => f ? f.length : 0));
|
||||
return (maxFrames || 0) + 1;
|
||||
}
|
||||
if (sheet.rows !== undefined) {
|
||||
return sheet.rows;
|
||||
} else {
|
||||
const sets = getSetsForFirstKey(sheet);
|
||||
const maxFrames = sets && max(sets.map(f => f ? f.length : 0));
|
||||
return (maxFrames || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
export function savePsd(psd: Psd, name: string) {
|
||||
saveAs(new Blob([writePsd(psd, { generateThumbnail: true })], { type: 'application/octet-stream' }), name);
|
||||
saveAs(new Blob([writePsd(psd, { generateThumbnail: true })], { type: 'application/octet-stream' }), name);
|
||||
}
|
||||
|
||||
export function createPsd(sheet: Sheet, rows: number, cols: number): Psd {
|
||||
const width = canvasWidth(sheet, rows, cols);
|
||||
const height = canvasHeight(sheet, rows, cols);
|
||||
const width = canvasWidth(sheet, rows, cols);
|
||||
const height = canvasHeight(sheet, rows, cols);
|
||||
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
children: compact([
|
||||
{ name: '<bg>', canvas: createBackground(rows, cols, width, height, sheet), transparencyProtected: true },
|
||||
...sheet.layers!.map(layer => createPsdLayer(sheet, rows, cols, layer)),
|
||||
{ name: '<refs>', canvas: createRefsCanvas(width, height, sheet.paletteOffsetY) },
|
||||
]),
|
||||
};
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
children: compact([
|
||||
{ name: '<bg>', canvas: createBackground(rows, cols, width, height, sheet), transparencyProtected: true },
|
||||
...sheet.layers!.map(layer => createPsdLayer(sheet, rows, cols, layer)),
|
||||
{ name: '<refs>', canvas: createRefsCanvas(width, height, sheet.paletteOffsetY) },
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
function canvasWidth(sheet: Sheet, _rows: number, cols: number) {
|
||||
if (sheet.wrap) {
|
||||
cols = sheet.wrap;
|
||||
}
|
||||
if (sheet.wrap) {
|
||||
cols = sheet.wrap;
|
||||
}
|
||||
|
||||
return (sheet.offset * (cols - 1)) + sheet.width;
|
||||
return (sheet.offset * (cols - 1)) + sheet.width;
|
||||
}
|
||||
|
||||
function canvasHeight(sheet: Sheet, rows: number, _cols: number) {
|
||||
if (sheet.wrap) {
|
||||
rows = Math.ceil(rows / sheet.wrap);
|
||||
}
|
||||
if (sheet.wrap) {
|
||||
rows = Math.ceil(rows / sheet.wrap);
|
||||
}
|
||||
|
||||
return sheet.height * rows;
|
||||
return sheet.height * rows;
|
||||
}
|
||||
|
||||
function drawPsdLayer(
|
||||
sheet: Sheet, rows: number, cols: number, layer: SheetLayer, pattern = -1, extra = false
|
||||
sheet: Sheet, rows: number, cols: number, layer: SheetLayer, pattern = -1, extra = false
|
||||
): HTMLCanvasElement {
|
||||
const { width, height, offset, offsetY = 0, wrap } = sheet;
|
||||
const pony = createPony();
|
||||
const baseState = { ...defaultPonyState(), ...sheet.state, blushColor: BLACK };
|
||||
const options = { ...defaultDrawPonyOptions(), ...layer.options };
|
||||
const ignoreColor = (layer.drawBlack === undefined ? !!layer.head : layer.drawBlack) ? TRANSPARENT : BLACK;
|
||||
const fieldName = layer.fieldName || sheet.fieldName;
|
||||
const { width, height, offset, offsetY = 0, wrap } = sheet;
|
||||
const pony = createPony();
|
||||
const baseState = { ...defaultPonyState(), ...sheet.state, blushColor: BLACK };
|
||||
const options = { ...defaultDrawPonyOptions(), ...layer.options };
|
||||
const ignoreColor = (layer.drawBlack === undefined ? !!layer.head : layer.drawBlack) ? TRANSPARENT : BLACK;
|
||||
const fieldName = layer.fieldName || sheet.fieldName;
|
||||
|
||||
if (!layer.head) {
|
||||
baseState.headAnimation = createHeadAnimation('', 1, false, [[]]);
|
||||
pony.head = ignoreSet();
|
||||
pony.nose = ignoreSet();
|
||||
pony.ears = ignoreSet();
|
||||
} else if (layer.noFace) {
|
||||
baseState.headAnimation = createHeadAnimation('', 1, false, [[]]);
|
||||
pony.head = ignoreSet();
|
||||
pony.nose = ignoreSet();
|
||||
}
|
||||
if (!layer.head) {
|
||||
baseState.headAnimation = createHeadAnimation('', 1, false, [[]]);
|
||||
pony.head = ignoreSet();
|
||||
pony.nose = ignoreSet();
|
||||
pony.ears = ignoreSet();
|
||||
} else if (layer.noFace) {
|
||||
baseState.headAnimation = createHeadAnimation('', 1, false, [[]]);
|
||||
pony.head = ignoreSet();
|
||||
pony.nose = ignoreSet();
|
||||
}
|
||||
|
||||
if (!layer.body) {
|
||||
options.no = setFlag(options.no, NoDraw.BodyOnly, true);
|
||||
}
|
||||
if (!layer.body) {
|
||||
options.no = setFlag(options.no, NoDraw.BodyOnly, true);
|
||||
}
|
||||
|
||||
if (!layer.frontLeg) {
|
||||
options.no = setFlag(options.no, NoDraw.FrontLeg, true);
|
||||
}
|
||||
if (!layer.frontLeg) {
|
||||
options.no = setFlag(options.no, NoDraw.FrontLeg, true);
|
||||
}
|
||||
|
||||
if (!layer.backLeg) {
|
||||
options.no = setFlag(options.no, NoDraw.BackLeg, true);
|
||||
}
|
||||
if (!layer.backLeg) {
|
||||
options.no = setFlag(options.no, NoDraw.BackLeg, true);
|
||||
}
|
||||
|
||||
if (!layer.frontFarLeg) {
|
||||
options.no = setFlag(options.no, NoDraw.FrontFarLeg, true);
|
||||
}
|
||||
if (!layer.frontFarLeg) {
|
||||
options.no = setFlag(options.no, NoDraw.FrontFarLeg, true);
|
||||
}
|
||||
|
||||
if (!layer.backFarLeg) {
|
||||
options.no = setFlag(options.no, NoDraw.BackFarLeg, true);
|
||||
}
|
||||
if (!layer.backFarLeg) {
|
||||
options.no = setFlag(options.no, NoDraw.BackFarLeg, true);
|
||||
}
|
||||
|
||||
layer.setup && layer.setup(pony, baseState);
|
||||
layer.setup && layer.setup(pony, baseState);
|
||||
|
||||
syncLockedPonyInfoNumber(pony);
|
||||
syncLockedPonyInfoNumber(pony);
|
||||
|
||||
const actualRows = wrap ? Math.ceil(rows / wrap) : rows;
|
||||
const actualCols = wrap ? wrap : cols;
|
||||
const empties = sheet.empties && includes(sheet.setsWithEmpties, layer.set) ? sheet.empties : [];
|
||||
const actualRows = wrap ? Math.ceil(rows / wrap) : rows;
|
||||
const actualCols = wrap ? wrap : cols;
|
||||
const empties = sheet.empties && includes(sheet.setsWithEmpties, layer.set) ? sheet.empties : [];
|
||||
|
||||
return drawFrames(actualRows, actualCols, width, height, offset, (batch, x, y) => {
|
||||
const xIndexBase = (wrap ? actualCols * y + x : x);
|
||||
const xIndexOffset = empties.filter(i => i <= xIndexBase).length;
|
||||
const xIndex = includes(empties, xIndexBase) ? 0 : (xIndexBase - xIndexOffset);
|
||||
const yIndex = wrap ? 0 : y;
|
||||
return drawFrames(actualRows, actualCols, width, height, offset, (batch, x, y) => {
|
||||
const xIndexBase = (wrap ? actualCols * y + x : x);
|
||||
const xIndexOffset = empties.filter(i => i <= xIndexBase).length;
|
||||
const xIndex = includes(empties, xIndexBase) ? 0 : (xIndexBase - xIndexOffset);
|
||||
const yIndex = wrap ? 0 : y;
|
||||
|
||||
const state = cloneDeep(baseState);
|
||||
const state = cloneDeep(baseState);
|
||||
|
||||
sheet.frame && sheet.frame(pony, state, options, xIndex, yIndex, pattern);
|
||||
layer.frame && layer.frame(pony, state, options, xIndex, yIndex, pattern);
|
||||
sheet.frame && sheet.frame(pony, state, options, xIndex, yIndex, pattern);
|
||||
layer.frame && layer.frame(pony, state, options, xIndex, yIndex, pattern);
|
||||
|
||||
state.animationFrame = xIndex;
|
||||
state.animationFrame = xIndex;
|
||||
|
||||
if (layer.set && fieldName) {
|
||||
const sets = getSets(sheet, layer.set, layer.setOverride);
|
||||
if (layer.set && fieldName) {
|
||||
const sets = getSets(sheet, layer.set, layer.setOverride);
|
||||
|
||||
if (!sets) {
|
||||
throw new Error(`Missing sets for (${layer.set})`);
|
||||
}
|
||||
if (!sets) {
|
||||
throw new Error(`Missing sets for (${layer.set})`);
|
||||
}
|
||||
|
||||
const frameIndex = sheet.single ? 0 : xIndex;
|
||||
const typeIndex = sheet.single ? xIndex : yIndex;
|
||||
const aframe = sets[frameIndex];
|
||||
const type = (aframe && typeIndex < aframe.length) ? typeIndex : -1;
|
||||
const set: SpriteSet<number> = { type };
|
||||
const frameIndex = sheet.single ? 0 : xIndex;
|
||||
const typeIndex = sheet.single ? xIndex : yIndex;
|
||||
const aframe = sets[frameIndex];
|
||||
const type = (aframe && typeIndex < aframe.length) ? typeIndex : -1;
|
||||
const set: SpriteSet<number> = { type };
|
||||
|
||||
if (pattern !== -1) {
|
||||
set.fills = patternColors;
|
||||
set.outlines = patternColors;
|
||||
if (pattern !== -1) {
|
||||
set.fills = patternColors;
|
||||
set.outlines = patternColors;
|
||||
|
||||
if (aframe && typeIndex < aframe.length && aframe[typeIndex] && pattern < aframe[typeIndex]!.length) {
|
||||
set.pattern = pattern;
|
||||
} else {
|
||||
set.type = -1;
|
||||
}
|
||||
} else {
|
||||
set.fills = whiteColors;
|
||||
set.outlines = whiteColors;
|
||||
if (aframe && typeIndex < aframe.length && aframe[typeIndex] && pattern < aframe[typeIndex]!.length) {
|
||||
set.pattern = pattern;
|
||||
} else {
|
||||
set.type = -1;
|
||||
}
|
||||
} else {
|
||||
set.fills = whiteColors;
|
||||
set.outlines = whiteColors;
|
||||
|
||||
if (!(aframe && typeIndex < aframe.length && aframe[typeIndex])) {
|
||||
set.type = -1;
|
||||
}
|
||||
}
|
||||
if (!(aframe && typeIndex < aframe.length && aframe[typeIndex])) {
|
||||
set.type = -1;
|
||||
}
|
||||
}
|
||||
|
||||
layer.frameSet && layer.frameSet(set, xIndex, yIndex, pattern);
|
||||
layer.frameSet && layer.frameSet(set, xIndex, yIndex, pattern);
|
||||
|
||||
(pony as any)[fieldName] = set.type === -1 ? ignoreSet() : set;
|
||||
}
|
||||
(pony as any)[fieldName] = set.type === -1 ? ignoreSet() : set;
|
||||
}
|
||||
|
||||
batch.disableShading = pattern !== -1;
|
||||
batch.ignoreColor = ignoreColor;
|
||||
batch.disableShading = pattern !== -1;
|
||||
batch.ignoreColor = ignoreColor;
|
||||
|
||||
const pal = toPaletteNumber(pony);
|
||||
const pal = toPaletteNumber(pony);
|
||||
|
||||
if (layer.extra !== undefined) {
|
||||
const set = pal[layer.extra] as PaletteSpriteSet;
|
||||
if (layer.extra !== undefined) {
|
||||
const set = pal[layer.extra] as PaletteSpriteSet;
|
||||
|
||||
if (extra) {
|
||||
set.palette = mockPaletteManager.add([0, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK]);
|
||||
} else {
|
||||
set.extraPalette = undefined;
|
||||
}
|
||||
}
|
||||
if (extra) {
|
||||
set.palette = mockPaletteManager.add([0, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK]);
|
||||
} else {
|
||||
set.extraPalette = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
drawPony(batch, pal, state, PONY_X, PONY_Y + offsetY + toInt(layer.shiftY), options);
|
||||
});
|
||||
drawPony(batch, pal, state, PONY_X, PONY_Y + offsetY + toInt(layer.shiftY), options);
|
||||
});
|
||||
}
|
||||
|
||||
function createPsdPatternLayers(sheet: Sheet, rows: number, cols: number, layer: SheetLayer): Layer[] {
|
||||
const sets = getSets(sheet, layer.set!, layer.setOverride);
|
||||
const patterns = layer.patterns || (sets ? maxPatterns(sets) : 0) || 6;
|
||||
const sets = getSets(sheet, layer.set!, layer.setOverride);
|
||||
const patterns = layer.patterns || (sets ? maxPatterns(sets) : 0) || 6;
|
||||
|
||||
return compact([
|
||||
layer.extra && {
|
||||
name: 'extra',
|
||||
canvas: drawPsdLayer(sheet, rows, cols, layer, -1, true),
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
canvas: drawPsdLayer(sheet, rows, cols, layer),
|
||||
},
|
||||
...times(patterns, i => ({
|
||||
name: `pattern ${i}`,
|
||||
canvas: drawPsdLayer(sheet, rows, cols, layer, i),
|
||||
hidden: true,
|
||||
clipping: true,
|
||||
blendMode: 'multiply',
|
||||
})),
|
||||
]);
|
||||
return compact([
|
||||
layer.extra && {
|
||||
name: 'extra',
|
||||
canvas: drawPsdLayer(sheet, rows, cols, layer, -1, true),
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
canvas: drawPsdLayer(sheet, rows, cols, layer),
|
||||
},
|
||||
...times(patterns, i => ({
|
||||
name: `pattern ${i}`,
|
||||
canvas: drawPsdLayer(sheet, rows, cols, layer, i),
|
||||
hidden: true,
|
||||
clipping: true,
|
||||
blendMode: 'multiply',
|
||||
})),
|
||||
]);
|
||||
}
|
||||
|
||||
function createPsdLayer(sheet: Sheet, rows: number, cols: number, layer: SheetLayer): Layer {
|
||||
const name = layer.name;
|
||||
const name = layer.name;
|
||||
|
||||
if (layer.set) {
|
||||
return { name, children: createPsdPatternLayers(sheet, rows, cols, layer) };
|
||||
} else {
|
||||
return { name, canvas: drawPsdLayer(sheet, rows, cols, layer) };
|
||||
}
|
||||
if (layer.set) {
|
||||
return { name, children: createPsdPatternLayers(sheet, rows, cols, layer) };
|
||||
} else {
|
||||
return { name, canvas: drawPsdLayer(sheet, rows, cols, layer) };
|
||||
}
|
||||
}
|
||||
|
||||
function drawFrames(
|
||||
rows: number, cols: number, w: number, h: number, offset: number,
|
||||
draw: (batch: ContextSpriteBatch, x: number, y: number) => void
|
||||
rows: number, cols: number, w: number, h: number, offset: number,
|
||||
draw: (batch: ContextSpriteBatch, x: number, y: number) => void
|
||||
): HTMLCanvasElement {
|
||||
const canvas = createCanvas((offset * (cols - 1)) + w, h * rows);
|
||||
const buffer = createCanvas(w, h);
|
||||
const batch = new ContextSpriteBatch(buffer);
|
||||
const viewContext = canvas.getContext('2d')!;
|
||||
viewContext.save();
|
||||
disableImageSmoothing(viewContext);
|
||||
const canvas = createCanvas((offset * (cols - 1)) + w, h * rows);
|
||||
const buffer = createCanvas(w, h);
|
||||
const batch = new ContextSpriteBatch(buffer);
|
||||
const viewContext = canvas.getContext('2d')!;
|
||||
viewContext.save();
|
||||
disableImageSmoothing(viewContext);
|
||||
|
||||
for (let y = 0; y < rows; y++) {
|
||||
for (let x = 0; x < cols; x++) {
|
||||
batch.start(sprites.paletteSpriteSheet, 0);
|
||||
draw(batch, x, y);
|
||||
batch.end();
|
||||
viewContext.drawImage(buffer, x * offset, y * h);
|
||||
}
|
||||
}
|
||||
for (let y = 0; y < rows; y++) {
|
||||
for (let x = 0; x < cols; x++) {
|
||||
batch.start(sprites.paletteSpriteSheet, 0);
|
||||
draw(batch, x, y);
|
||||
batch.end();
|
||||
viewContext.drawImage(buffer, x * offset, y * h);
|
||||
}
|
||||
}
|
||||
|
||||
viewContext.restore();
|
||||
return canvas;
|
||||
viewContext.restore();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function createBackground(rows: number, cols: number, width: number, height: number, sheet: Sheet) {
|
||||
const canvas = createCanvas(width, height);
|
||||
const context = canvas.getContext('2d')!;
|
||||
const canvas = createCanvas(width, height);
|
||||
const context = canvas.getContext('2d')!;
|
||||
|
||||
if (sheet.wrap) {
|
||||
cols = sheet.wrap;
|
||||
rows = Math.ceil(rows / sheet.wrap);
|
||||
}
|
||||
if (sheet.wrap) {
|
||||
cols = sheet.wrap;
|
||||
rows = Math.ceil(rows / sheet.wrap);
|
||||
}
|
||||
|
||||
fillRect(context, 'lightgreen', 0, 0, canvas.width, canvas.height);
|
||||
fillRect(context, 'lightgreen', 0, 0, canvas.width, canvas.height);
|
||||
|
||||
context.globalAlpha = 0.1;
|
||||
context.globalAlpha = 0.1;
|
||||
|
||||
for (let y = 0; y < rows; y++) {
|
||||
for (let x = 0; x < cols; x++) {
|
||||
const color = (x + (y % 2)) % 2 ? 'green' : 'blue';
|
||||
fillRect(context, color, x * sheet.offset, y * sheet.height, sheet.width, sheet.height);
|
||||
}
|
||||
}
|
||||
for (let y = 0; y < rows; y++) {
|
||||
for (let x = 0; x < cols; x++) {
|
||||
const color = (x + (y % 2)) % 2 ? 'green' : 'blue';
|
||||
fillRect(context, color, x * sheet.offset, y * sheet.height, sheet.width, sheet.height);
|
||||
}
|
||||
}
|
||||
|
||||
context.globalAlpha = 1;
|
||||
context.globalAlpha = 1;
|
||||
|
||||
for (let y = 0; y < rows; y++) {
|
||||
for (let x = 0; x < cols; x++) {
|
||||
const gap = sheet.width - sheet.offset;
|
||||
const index = sheet.wrap ? (cols * y + x) : x;
|
||||
drawPixelTextOnCanvas(context, x * sheet.offset + gap + 2, y * sheet.height + 2, 0x76c189ff, index.toString());
|
||||
}
|
||||
}
|
||||
for (let y = 0; y < rows; y++) {
|
||||
for (let x = 0; x < cols; x++) {
|
||||
const gap = sheet.width - sheet.offset;
|
||||
const index = sheet.wrap ? (cols * y + x) : x;
|
||||
drawPixelTextOnCanvas(context, x * sheet.offset + gap + 2, y * sheet.height + 2, 0x76c189ff, index.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return canvas;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function createRefsCanvas(width: number, height: number, offsetY = 0) {
|
||||
const canvas = createCanvas(width, height);
|
||||
const context = canvas.getContext('2d')!;
|
||||
const h = 2;
|
||||
const canvas = createCanvas(width, height);
|
||||
const context = canvas.getContext('2d')!;
|
||||
const h = 2;
|
||||
|
||||
patternColors.forEach((c, i) => fillRect(context, colorToCSS(c), 5, 5 + h * i + offsetY, 10, h));
|
||||
patternColors.forEach((c, i) => fillRect(context, colorToCSS(c), 5, 5 + h * i + offsetY, 10, h));
|
||||
|
||||
fillRect(context, '#888888', 25, 10 + offsetY, 8, 10);
|
||||
fillRect(context, '#d9d9d9', 27, 12 + offsetY, 4, 4);
|
||||
fillRect(context, '#afafaf', 27, 16 + offsetY, 4, 2);
|
||||
fillRect(context, '#9f9f9f', 20, 5 + offsetY, 8, 10);
|
||||
fillRect(context, '#ffffff', 22, 7 + offsetY, 4, 4);
|
||||
fillRect(context, '#cdcdcd', 22, 11 + offsetY, 4, 2);
|
||||
fillRect(context, '#888888', 25, 10 + offsetY, 8, 10);
|
||||
fillRect(context, '#d9d9d9', 27, 12 + offsetY, 4, 4);
|
||||
fillRect(context, '#afafaf', 27, 16 + offsetY, 4, 2);
|
||||
fillRect(context, '#9f9f9f', 20, 5 + offsetY, 8, 10);
|
||||
fillRect(context, '#ffffff', 22, 7 + offsetY, 4, 4);
|
||||
fillRect(context, '#cdcdcd', 22, 11 + offsetY, 4, 2);
|
||||
|
||||
return canvas;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function createPony(): PonyInfoNumber {
|
||||
const pony = decompressPony(compressPonyString(createDefaultPony()));
|
||||
pony.mane!.type = 0;
|
||||
pony.backMane!.type = 0;
|
||||
pony.tail!.type = 0;
|
||||
pony.coatFill = DEFAULT_COLOR;
|
||||
pony.lockCoatOutline = true;
|
||||
pony.lockBackLegAccessory = false;
|
||||
return syncLockedPonyInfoNumber(pony);
|
||||
const pony = decompressPony(compressPonyString(createDefaultPony()));
|
||||
pony.mane!.type = 0;
|
||||
pony.backMane!.type = 0;
|
||||
pony.tail!.type = 0;
|
||||
pony.coatFill = DEFAULT_COLOR;
|
||||
pony.lockCoatOutline = true;
|
||||
pony.lockBackLegAccessory = false;
|
||||
return syncLockedPonyInfoNumber(pony);
|
||||
}
|
||||
|
||||
export function drawPsd(psd: Psd, scale: number, canvas?: HTMLCanvasElement): HTMLCanvasElement {
|
||||
const buffer = canvas || createCanvas(100, 100);
|
||||
buffer.width = psd.width * scale;
|
||||
buffer.height = psd.height * scale;
|
||||
const context = buffer.getContext('2d')!;
|
||||
context.save();
|
||||
context.scale(scale, scale);
|
||||
disableImageSmoothing(context);
|
||||
drawLayer(psd, context);
|
||||
context.restore();
|
||||
return buffer;
|
||||
const buffer = canvas || createCanvas(100, 100);
|
||||
buffer.width = psd.width * scale;
|
||||
buffer.height = psd.height * scale;
|
||||
const context = buffer.getContext('2d')!;
|
||||
context.save();
|
||||
context.scale(scale, scale);
|
||||
disableImageSmoothing(context);
|
||||
drawLayer(psd, context);
|
||||
context.restore();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function drawLayer(layer: Layer, context: CanvasRenderingContext2D) {
|
||||
if (!layer.hidden) {
|
||||
layer.canvas && context.drawImage(layer.canvas, 0, 0);
|
||||
layer.children && layer.children.forEach(c => drawLayer(c, context));
|
||||
}
|
||||
if (!layer.hidden) {
|
||||
layer.canvas && context.drawImage(layer.canvas, 0, 0);
|
||||
layer.children && layer.children.forEach(c => drawLayer(c, context));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
|
||||
import {
|
||||
drawSpeechBaloon, drawNamePlate, createCommonPalettes, drawBaloon, DrawNameFlags
|
||||
drawSpeechBaloon, drawNamePlate, createCommonPalettes, drawBaloon, DrawNameFlags
|
||||
} from '../../../graphics/graphicsUtils';
|
||||
import { drawCanvas } from '../../../graphics/contextSpriteBatch';
|
||||
import {
|
||||
GRASS_COLOR, getMessageColor, OUTLINE_COLOR, MOD_COLOR, ADMIN_COLOR, PATREON_COLOR, ANNOUNCEMENT_COLOR,
|
||||
WHITE, PARTY_COLOR, RED, ORANGE, PURPLE, GREEN, YELLOW, BLUE, BLACK, CYAN, TRANSPARENT, WHISPER_COLOR
|
||||
GRASS_COLOR, getMessageColor, OUTLINE_COLOR, MOD_COLOR, ADMIN_COLOR, PATREON_COLOR, ANNOUNCEMENT_COLOR,
|
||||
WHITE, PARTY_COLOR, RED, ORANGE, PURPLE, GREEN, YELLOW, BLUE, BLACK, CYAN, TRANSPARENT, WHISPER_COLOR
|
||||
} from '../../../common/colors';
|
||||
import { loadAndInitSpriteSheets } from '../../../client/spriteUtils';
|
||||
import { MessageType, FontPalettes, Palette } from '../../../common/interfaces';
|
||||
@@ -19,173 +19,173 @@ import { rect } from '../../../common/rect';
|
||||
import { colorToCSS } from '../../../common/color';
|
||||
|
||||
interface Message {
|
||||
label: string;
|
||||
color: number;
|
||||
palette?: (palettes: FontPalettes) => Palette | undefined;
|
||||
label: string;
|
||||
color: number;
|
||||
palette?: (palettes: FontPalettes) => Palette | undefined;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tools-chat',
|
||||
templateUrl: 'tools-chat.pug',
|
||||
selector: 'tools-chat',
|
||||
templateUrl: 'tools-chat.pug',
|
||||
})
|
||||
export class ToolsChat implements AfterViewInit {
|
||||
readonly homeIcon = faHome;
|
||||
readonly starIcon = faStar;
|
||||
@ViewChild('canvas', { static: true }) element!: ElementRef;
|
||||
messages: Message[] = [
|
||||
{ label: 'Chat message', color: getMessageColor(MessageType.Chat) },
|
||||
{ label: 'System message', color: getMessageColor(MessageType.System) },
|
||||
{ label: 'Admin message', color: getMessageColor(MessageType.Admin) },
|
||||
{ label: 'Mod message', color: getMessageColor(MessageType.Mod) },
|
||||
{ label: 'Announcement message', color: getMessageColor(MessageType.Announcement) },
|
||||
{ label: 'Party message', color: getMessageColor(MessageType.Party) },
|
||||
{ label: 'Thinking message', color: getMessageColor(MessageType.Thinking) },
|
||||
{ label: 'PartyThinking message', color: getMessageColor(MessageType.PartyThinking) },
|
||||
{ label: 'PartyAnnouncement message', color: getMessageColor(MessageType.PartyAnnouncement) },
|
||||
// {
|
||||
// label: 'PartyAnnouncement msg ⚧', color: WHITE,
|
||||
// palette: () => mockPaletteManager.add([
|
||||
// TRANSPARENT,
|
||||
// ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// ]),
|
||||
// },
|
||||
// {
|
||||
// label: 'PartyAnnouncement msg ⚧', color: WHITE,
|
||||
// palette: () => mockPaletteManager.add([
|
||||
// TRANSPARENT,
|
||||
// ANNOUNCEMENT_COLOR,
|
||||
// ANNOUNCEMENT_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// ANNOUNCEMENT_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// ANNOUNCEMENT_COLOR, PARTY_COLOR,
|
||||
// PARTY_COLOR, PARTY_COLOR,
|
||||
// PARTY_COLOR, PARTY_COLOR,
|
||||
// ]),
|
||||
// },
|
||||
// { label: 'Red message', color: getMessageColor(MessageType.Red) },
|
||||
// { label: 'Green message', color: getMessageColor(MessageType.Green) },
|
||||
// { label: 'Blue message', color: getMessageColor(MessageType.Blue) },
|
||||
{ label: 'Supporter message 1', color: getMessageColor(MessageType.Supporter1) },
|
||||
{ label: 'Supporter message 2', color: WHITE, palette: p => p.supporter2 },
|
||||
{ label: 'Supporter message 3', color: WHITE, palette: p => p.supporter3 },
|
||||
{ label: 'Whisper message', color: WHISPER_COLOR },
|
||||
// { label: 'Supporter message 2', color: 0xffd45aff },
|
||||
];
|
||||
names = [
|
||||
{ label: 'Regular name', color: WHITE, font: () => fontPal },
|
||||
{ label: 'Party name', color: PARTY_COLOR, font: () => fontPal },
|
||||
{ label: 'MODERATOR tag', color: MOD_COLOR, font: () => fontSmallPal },
|
||||
{ label: 'DEVELOPER tag', color: ADMIN_COLOR, font: () => fontSmallPal },
|
||||
{ label: 'SUPPORTER tag', color: PATREON_COLOR, font: () => fontSmallPal },
|
||||
{ label: 'HIDDEN tag', color: ANNOUNCEMENT_COLOR, font: () => fontSmallPal },
|
||||
];
|
||||
private bg = GRASS_COLOR;
|
||||
private initialized = false;
|
||||
ngAfterViewInit() {
|
||||
loadAndInitSpriteSheets()
|
||||
.then(() => this.initialized = true)
|
||||
.then(() => this.redraw());
|
||||
}
|
||||
toggleBg() {
|
||||
this.bg = this.bg === GRASS_COLOR ? 0x172e14ff : GRASS_COLOR;
|
||||
this.redraw();
|
||||
}
|
||||
redraw() {
|
||||
if (!this.initialized)
|
||||
return;
|
||||
readonly homeIcon = faHome;
|
||||
readonly starIcon = faStar;
|
||||
@ViewChild('canvas', { static: true }) element!: ElementRef;
|
||||
messages: Message[] = [
|
||||
{ label: 'Chat message', color: getMessageColor(MessageType.Chat) },
|
||||
{ label: 'System message', color: getMessageColor(MessageType.System) },
|
||||
{ label: 'Admin message', color: getMessageColor(MessageType.Admin) },
|
||||
{ label: 'Mod message', color: getMessageColor(MessageType.Mod) },
|
||||
{ label: 'Announcement message', color: getMessageColor(MessageType.Announcement) },
|
||||
{ label: 'Party message', color: getMessageColor(MessageType.Party) },
|
||||
{ label: 'Thinking message', color: getMessageColor(MessageType.Thinking) },
|
||||
{ label: 'PartyThinking message', color: getMessageColor(MessageType.PartyThinking) },
|
||||
{ label: 'PartyAnnouncement message', color: getMessageColor(MessageType.PartyAnnouncement) },
|
||||
// {
|
||||
// label: 'PartyAnnouncement msg ⚧', color: WHITE,
|
||||
// palette: () => mockPaletteManager.add([
|
||||
// TRANSPARENT,
|
||||
// ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// PARTY_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// ]),
|
||||
// },
|
||||
// {
|
||||
// label: 'PartyAnnouncement msg ⚧', color: WHITE,
|
||||
// palette: () => mockPaletteManager.add([
|
||||
// TRANSPARENT,
|
||||
// ANNOUNCEMENT_COLOR,
|
||||
// ANNOUNCEMENT_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// ANNOUNCEMENT_COLOR, ANNOUNCEMENT_COLOR,
|
||||
// ANNOUNCEMENT_COLOR, PARTY_COLOR,
|
||||
// PARTY_COLOR, PARTY_COLOR,
|
||||
// PARTY_COLOR, PARTY_COLOR,
|
||||
// ]),
|
||||
// },
|
||||
// { label: 'Red message', color: getMessageColor(MessageType.Red) },
|
||||
// { label: 'Green message', color: getMessageColor(MessageType.Green) },
|
||||
// { label: 'Blue message', color: getMessageColor(MessageType.Blue) },
|
||||
{ label: 'Supporter message 1', color: getMessageColor(MessageType.Supporter1) },
|
||||
{ label: 'Supporter message 2', color: WHITE, palette: p => p.supporter2 },
|
||||
{ label: 'Supporter message 3', color: WHITE, palette: p => p.supporter3 },
|
||||
{ label: 'Whisper message', color: WHISPER_COLOR },
|
||||
// { label: 'Supporter message 2', color: 0xffd45aff },
|
||||
];
|
||||
names = [
|
||||
{ label: 'Regular name', color: WHITE, font: () => fontPal },
|
||||
{ label: 'Party name', color: PARTY_COLOR, font: () => fontPal },
|
||||
{ label: 'MODERATOR tag', color: MOD_COLOR, font: () => fontSmallPal },
|
||||
{ label: 'DEVELOPER tag', color: ADMIN_COLOR, font: () => fontSmallPal },
|
||||
{ label: 'SUPPORTER tag', color: PATREON_COLOR, font: () => fontSmallPal },
|
||||
{ label: 'HIDDEN tag', color: ANNOUNCEMENT_COLOR, font: () => fontSmallPal },
|
||||
];
|
||||
private bg = GRASS_COLOR;
|
||||
private initialized = false;
|
||||
ngAfterViewInit() {
|
||||
loadAndInitSpriteSheets()
|
||||
.then(() => this.initialized = true)
|
||||
.then(() => this.redraw());
|
||||
}
|
||||
toggleBg() {
|
||||
this.bg = this.bg === GRASS_COLOR ? 0x172e14ff : GRASS_COLOR;
|
||||
this.redraw();
|
||||
}
|
||||
redraw() {
|
||||
if (!this.initialized)
|
||||
return;
|
||||
|
||||
const canvas1 = drawCanvas(500, 400, sprites.paletteSpriteSheet, undefined, batch => {
|
||||
const palettes = createCommonPalettes(mockPaletteManager);
|
||||
const canvas1 = drawCanvas(500, 400, sprites.paletteSpriteSheet, undefined, batch => {
|
||||
const palettes = createCommonPalettes(mockPaletteManager);
|
||||
|
||||
this.messages.forEach(({ label, color, palette }, index) => {
|
||||
const size = measureText(label, fontPal);
|
||||
const options = { palette: palette ? palette(palettes.mainFont) : palettes.mainFont.white };
|
||||
drawSpeechBaloon(batch, label, color, options, 10 + size.w / 2, 20 + 20 * index, size.w, size.h, 1, 5);
|
||||
});
|
||||
this.messages.forEach(({ label, color, palette }, index) => {
|
||||
const size = measureText(label, fontPal);
|
||||
const options = { palette: palette ? palette(palettes.mainFont) : palettes.mainFont.white };
|
||||
drawSpeechBaloon(batch, label, color, options, 10 + size.w / 2, 20 + 20 * index, size.w, size.h, 1, 5);
|
||||
});
|
||||
|
||||
this.names.forEach(({ label, color, font }, index) => {
|
||||
const palette = font() === fontSmallPal ? palettes.smallFont.white : palettes.mainFont.white;
|
||||
drawOutlinedText(batch, label, font(), color, OUTLINE_COLOR, 190, 10 + 15 * index, { palette });
|
||||
});
|
||||
this.names.forEach(({ label, color, font }, index) => {
|
||||
const palette = font() === fontSmallPal ? palettes.smallFont.white : palettes.mainFont.white;
|
||||
drawOutlinedText(batch, label, font(), color, OUTLINE_COLOR, 190, 10 + 15 * index, { palette });
|
||||
});
|
||||
|
||||
// ---
|
||||
// ---
|
||||
|
||||
drawOutlinedText(
|
||||
batch, '<SUPPORTER>', fontSmallPal, PATREON_COLOR, OUTLINE_COLOR, 190, 120, { palette: palettes.smallFont.white });
|
||||
drawOutlinedText(
|
||||
batch, '<SUPPORTER>', fontSmallPal, PATREON_COLOR, OUTLINE_COLOR, 190, 120, { palette: palettes.smallFont.white });
|
||||
|
||||
// names
|
||||
// names
|
||||
|
||||
drawNamePlate(batch, 'Some name 1', 220, 150, DrawNameFlags.None, palettes, 'sup1');
|
||||
drawNamePlate(batch, 'Some name 2', 220, 175, DrawNameFlags.None, palettes, 'sup2');
|
||||
drawNamePlate(batch, 'Some name 3', 220, 200, DrawNameFlags.None, palettes, 'sup3');
|
||||
drawNamePlate(batch, 'Some name 1', 220, 150, DrawNameFlags.None, palettes, 'sup1');
|
||||
drawNamePlate(batch, 'Some name 2', 220, 175, DrawNameFlags.None, palettes, 'sup2');
|
||||
drawNamePlate(batch, 'Some name 3', 220, 200, DrawNameFlags.None, palettes, 'sup3');
|
||||
|
||||
// speech baloons
|
||||
// speech baloons
|
||||
|
||||
drawBaloon(
|
||||
batch, { message: 'regular baloon', type: MessageType.Chat, created: 0 },
|
||||
50, 300, rect(0, 0, 1000, 1000), palettes);
|
||||
drawBaloon(
|
||||
batch, { message: 'thinking baloon', type: MessageType.Thinking, created: 0 },
|
||||
50, 330, rect(0, 0, 1000, 1000), palettes);
|
||||
drawBaloon(
|
||||
batch, { message: 'whisper baloon', type: MessageType.Whisper, created: 0 },
|
||||
50, 360, rect(0, 0, 1000, 1000), palettes);
|
||||
});
|
||||
drawBaloon(
|
||||
batch, { message: 'regular baloon', type: MessageType.Chat, created: 0 },
|
||||
50, 300, rect(0, 0, 1000, 1000), palettes);
|
||||
drawBaloon(
|
||||
batch, { message: 'thinking baloon', type: MessageType.Thinking, created: 0 },
|
||||
50, 330, rect(0, 0, 1000, 1000), palettes);
|
||||
drawBaloon(
|
||||
batch, { message: 'whisper baloon', type: MessageType.Whisper, created: 0 },
|
||||
50, 360, rect(0, 0, 1000, 1000), palettes);
|
||||
});
|
||||
|
||||
const canvas2 = drawCanvas(500, 400, sprites.paletteSpriteSheet, undefined, batch => {
|
||||
const emojiPalette = mockPaletteManager.addArray(sprites.emojiPalette);
|
||||
const canvas2 = drawCanvas(500, 400, sprites.paletteSpriteSheet, undefined, batch => {
|
||||
const emojiPalette = mockPaletteManager.addArray(sprites.emojiPalette);
|
||||
|
||||
for (let i = 0; i < sprites.emojiPal.length; i++) {
|
||||
const x = i % 10;
|
||||
const y = Math.floor(i / 10);
|
||||
batch.drawSprite(sprites.emojiPal[i].sprite, WHITE, emojiPalette, 10 + x * 12, 10 + y * 12);
|
||||
}
|
||||
for (let i = 0; i < sprites.emojiPal.length; i++) {
|
||||
const x = i % 10;
|
||||
const y = Math.floor(i / 10);
|
||||
batch.drawSprite(sprites.emojiPal[i].sprite, WHITE, emojiPalette, 10 + x * 12, 10 + y * 12);
|
||||
}
|
||||
|
||||
const palette = mockPaletteManager.addArray(sprites.fontSupporter2Palette);
|
||||
drawText(batch, 'Lorem 🍎 ipsum', fontPal, WHITE, 10, 150, { palette, emojiPalette });
|
||||
const palette = mockPaletteManager.addArray(sprites.fontSupporter2Palette);
|
||||
drawText(batch, 'Lorem 🍎 ipsum', fontPal, WHITE, 10, 150, { palette, emojiPalette });
|
||||
|
||||
const palette1 = mockPaletteManager.addArray(sprites.fontSupporter1Palette);
|
||||
drawText(batch, '<SUPPÓĄRTER>', fontSmallPal, WHITE, 20, 180, { palette: palette1 });
|
||||
const palette1 = mockPaletteManager.addArray(sprites.fontSupporter1Palette);
|
||||
drawText(batch, '<SUPPÓĄRTER>', fontSmallPal, WHITE, 20, 180, { palette: palette1 });
|
||||
|
||||
const palette2 = mockPaletteManager.addArray(sprites.fontSupporter2Palette);
|
||||
drawText(batch, '<SUPPÓĄRTER>', fontSmallPal, WHITE, 20, 195, { palette: palette2 });
|
||||
const palette2 = mockPaletteManager.addArray(sprites.fontSupporter2Palette);
|
||||
drawText(batch, '<SUPPÓĄRTER>', fontSmallPal, WHITE, 20, 195, { palette: palette2 });
|
||||
|
||||
let palette3 = mockPaletteManager.add([TRANSPARENT, RED, BLUE, ORANGE, WHITE, PURPLE, BLACK, GREEN, CYAN, YELLOW]);
|
||||
palette3 = mockPaletteManager.addArray(sprites.fontSupporter3Palette);
|
||||
drawText(batch, '<SUPPÓĄ⚧RTER>', fontSmallPal, WHITE, 20, 210, { palette: palette3 });
|
||||
});
|
||||
let palette3 = mockPaletteManager.add([TRANSPARENT, RED, BLUE, ORANGE, WHITE, PURPLE, BLACK, GREEN, CYAN, YELLOW]);
|
||||
palette3 = mockPaletteManager.addArray(sprites.fontSupporter3Palette);
|
||||
drawText(batch, '<SUPPÓĄ⚧RTER>', fontSmallPal, WHITE, 20, 210, { palette: palette3 });
|
||||
});
|
||||
|
||||
const canvas3 = drawCanvas(500, 400, sprites.paletteSpriteSheet, undefined, batch => {
|
||||
/* tslint:disable */
|
||||
const loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce scelerisque interdum scelerisque. Suspendisse malesuada, enim in viverra ornare, dui ex laoreet ipsum, at mollis orci felis vitae ipsum. In faucibus venenatis augue, ac ornare libero. Etiam vitae aliquet neque.';
|
||||
const text = lineBreak(loremIpsum, fontPal, 200);
|
||||
const canvas3 = drawCanvas(500, 400, sprites.paletteSpriteSheet, undefined, batch => {
|
||||
/* tslint:disable */
|
||||
const loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce scelerisque interdum scelerisque. Suspendisse malesuada, enim in viverra ornare, dui ex laoreet ipsum, at mollis orci felis vitae ipsum. In faucibus venenatis augue, ac ornare libero. Etiam vitae aliquet neque.';
|
||||
const text = lineBreak(loremIpsum, fontPal, 200);
|
||||
|
||||
batch.drawRect(WHITE, 10, 10, 200, 100);
|
||||
drawText(batch, text, fontPal, BLACK, 10, 10);
|
||||
batch.drawRect(WHITE, 10, 10, 200, 100);
|
||||
drawText(batch, text, fontPal, BLACK, 10, 10);
|
||||
|
||||
const bounds = rect(10 + 200 + 20, 10, 200, 100);
|
||||
batch.drawRect(WHITE, bounds.x, bounds.y, bounds.w, bounds.h);
|
||||
drawTextAligned(batch, text, fontPal, BLACK, bounds, HAlign.Right);
|
||||
const bounds = rect(10 + 200 + 20, 10, 200, 100);
|
||||
batch.drawRect(WHITE, bounds.x, bounds.y, bounds.w, bounds.h);
|
||||
drawTextAligned(batch, text, fontPal, BLACK, bounds, HAlign.Right);
|
||||
|
||||
const bounds2 = rect(10 + 200 + 20, 10 + 120, 200, 20);
|
||||
batch.drawRect(WHITE, bounds2.x, bounds2.y, bounds2.w, bounds2.h);
|
||||
drawTextAligned(batch, 'test text', fontPal, BLACK, bounds2, HAlign.Right);
|
||||
});
|
||||
const bounds2 = rect(10 + 200 + 20, 10 + 120, 200, 20);
|
||||
batch.drawRect(WHITE, bounds2.x, bounds2.y, bounds2.w, bounds2.h);
|
||||
drawTextAligned(batch, 'test text', fontPal, BLACK, bounds2, HAlign.Right);
|
||||
});
|
||||
|
||||
const canvas = this.element.nativeElement as HTMLCanvasElement;
|
||||
const context = canvas.getContext('2d')!;
|
||||
context.fillStyle = colorToCSS(this.bg);
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
disableImageSmoothing(context);
|
||||
context.save();
|
||||
context.scale(2, 2);
|
||||
context.drawImage(canvas1, 0, 0);
|
||||
context.drawImage(canvas2, 300, 0);
|
||||
context.drawImage(canvas3, 0, 400);
|
||||
context.restore();
|
||||
}
|
||||
const canvas = this.element.nativeElement as HTMLCanvasElement;
|
||||
const context = canvas.getContext('2d')!;
|
||||
context.fillStyle = colorToCSS(this.bg);
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
disableImageSmoothing(context);
|
||||
context.save();
|
||||
context.scale(2, 2);
|
||||
context.drawImage(canvas1, 0, 0);
|
||||
context.drawImage(canvas2, 300, 0);
|
||||
context.drawImage(canvas3, 0, 400);
|
||||
context.restore();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -36,388 +36,388 @@ const X = 128;
|
||||
const Y = 190;
|
||||
|
||||
const colors: Dict<number> = {
|
||||
cover: COVER,
|
||||
collider: COLLIDER,
|
||||
pickable: PICKABLE,
|
||||
cover: COVER,
|
||||
collider: COLLIDER,
|
||||
pickable: PICKABLE,
|
||||
};
|
||||
|
||||
interface BasePart {
|
||||
x: number;
|
||||
y: number;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface BoundsPart extends BasePart {
|
||||
w: number;
|
||||
h: number;
|
||||
w: number;
|
||||
h: number;
|
||||
}
|
||||
|
||||
interface SpritePart extends BasePart {
|
||||
type: 'sprite';
|
||||
sprite: string;
|
||||
type: 'sprite';
|
||||
sprite: string;
|
||||
}
|
||||
|
||||
interface CoverPart extends BoundsPart {
|
||||
type: 'cover';
|
||||
type: 'cover';
|
||||
}
|
||||
|
||||
interface ColliderPart extends BoundsPart {
|
||||
type: 'collider';
|
||||
type: 'collider';
|
||||
}
|
||||
|
||||
interface PickablePart extends BasePart {
|
||||
type: 'pickable';
|
||||
type: 'pickable';
|
||||
}
|
||||
|
||||
type Part = SpritePart | CoverPart | ColliderPart | PickablePart;
|
||||
|
||||
interface PartEntity {
|
||||
name: string;
|
||||
parts: Part[];
|
||||
name: string;
|
||||
parts: Part[];
|
||||
}
|
||||
|
||||
interface EntityData {
|
||||
parts?: Part[];
|
||||
entities?: PartEntity[];
|
||||
parts?: Part[];
|
||||
entities?: PartEntity[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tools-entity',
|
||||
templateUrl: 'tools-entity.pug',
|
||||
selector: 'tools-entity',
|
||||
templateUrl: 'tools-entity.pug',
|
||||
})
|
||||
export class ToolsEntity implements OnInit {
|
||||
readonly homeIcon = faHome;
|
||||
readonly saveIcon = faSave;
|
||||
readonly eraserIcon = faEraser;
|
||||
readonly trashIcon = faTrash;
|
||||
readonly crosshairsIcon = faCrosshairs;
|
||||
readonly plusIcon = faPlus;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
scale = 2;
|
||||
name = '';
|
||||
drawCenter = true;
|
||||
drawSelection = true;
|
||||
drawHold = false;
|
||||
sprites = Object.keys(sprites).filter(key => {
|
||||
const s = (sprites as any)[key] as any;
|
||||
return !!(s && s.color);
|
||||
});
|
||||
selectedPart = -1;
|
||||
entities: PartEntity[] = [];
|
||||
parts: Part[] = [];
|
||||
pony = toPalette(decompressPonyString(OFFLINE_PONY), mockPaletteManager);
|
||||
private startX = 0;
|
||||
private startY = 0;
|
||||
constructor(private storage: StorageService) {
|
||||
}
|
||||
ngOnInit() {
|
||||
setPaletteManager(paletteManager);
|
||||
loadAndInitSpriteSheets().then(() => this.changed());
|
||||
readonly homeIcon = faHome;
|
||||
readonly saveIcon = faSave;
|
||||
readonly eraserIcon = faEraser;
|
||||
readonly trashIcon = faTrash;
|
||||
readonly crosshairsIcon = faCrosshairs;
|
||||
readonly plusIcon = faPlus;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
scale = 2;
|
||||
name = '';
|
||||
drawCenter = true;
|
||||
drawSelection = true;
|
||||
drawHold = false;
|
||||
sprites = Object.keys(sprites).filter(key => {
|
||||
const s = (sprites as any)[key] as any;
|
||||
return !!(s && s.color);
|
||||
});
|
||||
selectedPart = -1;
|
||||
entities: PartEntity[] = [];
|
||||
parts: Part[] = [];
|
||||
pony = toPalette(decompressPonyString(OFFLINE_PONY), mockPaletteManager);
|
||||
private startX = 0;
|
||||
private startY = 0;
|
||||
constructor(private storage: StorageService) {
|
||||
}
|
||||
ngOnInit() {
|
||||
setPaletteManager(paletteManager);
|
||||
loadAndInitSpriteSheets().then(() => this.changed());
|
||||
|
||||
const data = this.load();
|
||||
this.parts = compact(data.parts || [this.createSpritePart('apple')]);
|
||||
this.entities = compact(data.entities || []);
|
||||
}
|
||||
@HostListener('window:keydown', ['$event'])
|
||||
keydown(e: KeyboardEvent) {
|
||||
if (!isKeyEventInvalid(e) && this.handleKey(e.keyCode)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
handleKey(keyCode: number) {
|
||||
if (keyCode === Key.UP) {
|
||||
this.movePart(0, -1);
|
||||
} else if (keyCode === Key.DOWN) {
|
||||
this.movePart(0, 1);
|
||||
} else if (keyCode === Key.LEFT) {
|
||||
this.movePart(-1, 0);
|
||||
} else if (keyCode === Key.RIGHT) {
|
||||
this.movePart(1, 0);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const data = this.load();
|
||||
this.parts = compact(data.parts || [this.createSpritePart('apple')]);
|
||||
this.entities = compact(data.entities || []);
|
||||
}
|
||||
@HostListener('window:keydown', ['$event'])
|
||||
keydown(e: KeyboardEvent) {
|
||||
if (!isKeyEventInvalid(e) && this.handleKey(e.keyCode)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
handleKey(keyCode: number) {
|
||||
if (keyCode === Key.UP) {
|
||||
this.movePart(0, -1);
|
||||
} else if (keyCode === Key.DOWN) {
|
||||
this.movePart(0, 1);
|
||||
} else if (keyCode === Key.LEFT) {
|
||||
this.movePart(-1, 0);
|
||||
} else if (keyCode === Key.RIGHT) {
|
||||
this.movePart(1, 0);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
mousedown(e: MouseEvent) {
|
||||
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
|
||||
const { left, top } = canvas.getBoundingClientRect();
|
||||
const x = (e.pageX - left) / this.scale - X;
|
||||
const y = (e.pageY - top) / this.scale - Y;
|
||||
return true;
|
||||
}
|
||||
mousedown(e: MouseEvent) {
|
||||
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
|
||||
const { left, top } = canvas.getBoundingClientRect();
|
||||
const x = (e.pageX - left) / this.scale - X;
|
||||
const y = (e.pageY - top) / this.scale - Y;
|
||||
|
||||
this.selectedPart = findLastIndex(this.parts, p => {
|
||||
if (this.drawHold) {
|
||||
return p.type === 'pickable';
|
||||
} else {
|
||||
const bounds = getBounds(p);
|
||||
return !!bounds && containsPoint(0, 0, bounds, x, y);
|
||||
}
|
||||
});
|
||||
this.selectedPart = findLastIndex(this.parts, p => {
|
||||
if (this.drawHold) {
|
||||
return p.type === 'pickable';
|
||||
} else {
|
||||
const bounds = getBounds(p);
|
||||
return !!bounds && containsPoint(0, 0, bounds, x, y);
|
||||
}
|
||||
});
|
||||
|
||||
this.changed();
|
||||
}
|
||||
drag({ dx, dy, type }: AgDragEvent) {
|
||||
const part = this.parts[this.selectedPart];
|
||||
this.changed();
|
||||
}
|
||||
drag({ dx, dy, type }: AgDragEvent) {
|
||||
const part = this.parts[this.selectedPart];
|
||||
|
||||
if (part) {
|
||||
if (type === 'start') {
|
||||
this.startX = part.x;
|
||||
this.startY = part.y;
|
||||
}
|
||||
if (part) {
|
||||
if (type === 'start') {
|
||||
this.startX = part.x;
|
||||
this.startY = part.y;
|
||||
}
|
||||
|
||||
part.x = Math.round(this.startX + dx / this.scale);
|
||||
part.y = Math.round(this.startY + dy / this.scale);
|
||||
}
|
||||
part.x = Math.round(this.startX + dx / this.scale);
|
||||
part.y = Math.round(this.startY + dy / this.scale);
|
||||
}
|
||||
|
||||
this.changed();
|
||||
}
|
||||
setEntity(entity: PartEntity | null) {
|
||||
if (entity) {
|
||||
this.name = entity.name;
|
||||
this.parts = entity.parts;
|
||||
} else {
|
||||
this.name = '';
|
||||
this.parts = [];
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
setEntity(entity: PartEntity | null) {
|
||||
if (entity) {
|
||||
this.name = entity.name;
|
||||
this.parts = entity.parts;
|
||||
} else {
|
||||
this.name = '';
|
||||
this.parts = [];
|
||||
}
|
||||
|
||||
this.changed();
|
||||
}
|
||||
saveEntity() {
|
||||
if (this.name) {
|
||||
const existing = this.entities.find(e => e.name === this.name);
|
||||
this.changed();
|
||||
}
|
||||
saveEntity() {
|
||||
if (this.name) {
|
||||
const existing = this.entities.find(e => e.name === this.name);
|
||||
|
||||
if (existing) {
|
||||
existing.parts = cloneDeep(this.parts);
|
||||
} else {
|
||||
this.entities.push({
|
||||
name: this.name,
|
||||
parts: cloneDeep(this.parts),
|
||||
});
|
||||
}
|
||||
if (existing) {
|
||||
existing.parts = cloneDeep(this.parts);
|
||||
} else {
|
||||
this.entities.push({
|
||||
name: this.name,
|
||||
parts: cloneDeep(this.parts),
|
||||
});
|
||||
}
|
||||
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
removeEntity() {
|
||||
removeItem(this.entities, this.entities.find(e => e.name === this.name));
|
||||
this.changed();
|
||||
}
|
||||
movePart(dx: number, dy: number) {
|
||||
const part = this.parts[this.selectedPart];
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
removeEntity() {
|
||||
removeItem(this.entities, this.entities.find(e => e.name === this.name));
|
||||
this.changed();
|
||||
}
|
||||
movePart(dx: number, dy: number) {
|
||||
const part = this.parts[this.selectedPart];
|
||||
|
||||
if (part) {
|
||||
part.x += dx;
|
||||
part.y += dy;
|
||||
}
|
||||
if (part) {
|
||||
part.x += dx;
|
||||
part.y += dy;
|
||||
}
|
||||
|
||||
this.changed();
|
||||
}
|
||||
changed() {
|
||||
requestAnimationFrame(() => this.redraw());
|
||||
}
|
||||
redraw() {
|
||||
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
|
||||
const scale = this.scale;
|
||||
const width = Math.ceil(canvas.width / scale);
|
||||
const height = Math.ceil(canvas.height / scale);
|
||||
this.changed();
|
||||
}
|
||||
changed() {
|
||||
requestAnimationFrame(() => this.redraw());
|
||||
}
|
||||
redraw() {
|
||||
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
|
||||
const scale = this.scale;
|
||||
const width = Math.ceil(canvas.width / scale);
|
||||
const height = Math.ceil(canvas.height / scale);
|
||||
|
||||
const draw = (batch: ContextSpriteBatch) => {
|
||||
if (this.drawCenter) {
|
||||
batch.drawRect(LINES, 0, Y, width, 1);
|
||||
batch.drawRect(LINES, X, 0, 1, height);
|
||||
}
|
||||
const draw = (batch: ContextSpriteBatch) => {
|
||||
if (this.drawCenter) {
|
||||
batch.drawRect(LINES, 0, Y, width, 1);
|
||||
batch.drawRect(LINES, X, 0, 1, height);
|
||||
}
|
||||
|
||||
this.parts.forEach(p => drawPart(batch, p, X, Y));
|
||||
this.parts.forEach(p => drawPart(batch, p, X, Y));
|
||||
|
||||
const part = this.parts[this.selectedPart] as Part | undefined;
|
||||
const part = this.parts[this.selectedPart] as Part | undefined;
|
||||
|
||||
if (part) {
|
||||
const bounds = getBounds(part);
|
||||
if (part) {
|
||||
const bounds = getBounds(part);
|
||||
|
||||
if (this.drawSelection && bounds) {
|
||||
const sx = X + bounds.x;
|
||||
const sy = Y + bounds.y;
|
||||
drawOutline(batch, SELECTION, sx - 1, sy - 1, bounds.w + 2, bounds.h + 2);
|
||||
}
|
||||
}
|
||||
if (this.drawSelection && bounds) {
|
||||
const sx = X + bounds.x;
|
||||
const sy = Y + bounds.y;
|
||||
drawOutline(batch, SELECTION, sx - 1, sy - 1, bounds.w + 2, bounds.h + 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawCenter) {
|
||||
batch.drawRect(RED, X, Y, 1, 1);
|
||||
}
|
||||
};
|
||||
if (this.drawCenter) {
|
||||
batch.drawRect(RED, X, Y, 1, 1);
|
||||
}
|
||||
};
|
||||
|
||||
const buffer = drawCanvas(width, height, sprites.paletteSpriteSheet, BG, batch => {
|
||||
if (this.drawHold) {
|
||||
const spritePart = this.parts.find(p => p.type === 'sprite') as SpritePart | undefined;
|
||||
const pickablePart = this.parts.find(p => p.type === 'pickable') as PickablePart | undefined;
|
||||
const buffer = drawCanvas(width, height, sprites.paletteSpriteSheet, BG, batch => {
|
||||
if (this.drawHold) {
|
||||
const spritePart = this.parts.find(p => p.type === 'sprite') as SpritePart | undefined;
|
||||
const pickablePart = this.parts.find(p => p.type === 'pickable') as PickablePart | undefined;
|
||||
|
||||
const holding: Entity | undefined = spritePart && pickablePart && getSprite(spritePart.sprite) ? {
|
||||
...createBaseEntity(0, 0, 0, 0),
|
||||
...drawMixin(getSprite(spritePart.sprite), -spritePart.x, -spritePart.y),
|
||||
...pickable(pickablePart.x, pickablePart.y),
|
||||
} : undefined;
|
||||
const holding: Entity | undefined = spritePart && pickablePart && getSprite(spritePart.sprite) ? {
|
||||
...createBaseEntity(0, 0, 0, 0),
|
||||
...drawMixin(getSprite(spritePart.sprite), -spritePart.x, -spritePart.y),
|
||||
...pickable(pickablePart.x, pickablePart.y),
|
||||
} : undefined;
|
||||
|
||||
const state = { ...defaultPonyState(), holding };
|
||||
drawPony(batch, this.pony, state, X, Y, defaultDrawPonyOptions());
|
||||
} else {
|
||||
draw(batch);
|
||||
}
|
||||
});
|
||||
const state = { ...defaultPonyState(), holding };
|
||||
drawPony(batch, this.pony, state, X, Y, defaultDrawPonyOptions());
|
||||
} else {
|
||||
draw(batch);
|
||||
}
|
||||
});
|
||||
|
||||
drawBufferScaled(canvas, buffer, scale);
|
||||
drawBufferScaled(canvas, buffer, scale);
|
||||
|
||||
this.save();
|
||||
}
|
||||
createSpritePart(sprite: string): SpritePart {
|
||||
return {
|
||||
type: 'sprite',
|
||||
sprite,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
}
|
||||
createBoundsPart(type: any): CoverPart {
|
||||
return {
|
||||
type,
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 10,
|
||||
h: 10,
|
||||
};
|
||||
}
|
||||
createPart(type: string): Part {
|
||||
switch (type) {
|
||||
case 'sprite':
|
||||
return this.createSpritePart('apple');
|
||||
case 'cover':
|
||||
case 'collider':
|
||||
return this.createBoundsPart(type);
|
||||
case 'pickable':
|
||||
return { type, x: 0, y: 0 };
|
||||
default:
|
||||
throw new Error(`Invalid type (${type})`);
|
||||
}
|
||||
}
|
||||
addPart(type: string) {
|
||||
this.parts.push(this.createPart(type));
|
||||
this.changed();
|
||||
}
|
||||
removePart(part: Part) {
|
||||
removeItem(this.parts, part);
|
||||
this.changed();
|
||||
}
|
||||
centerPart(part: Part) {
|
||||
if (part.type === 'sprite') {
|
||||
const sprite = getSprite(part.sprite);
|
||||
const color = sprite && sprite.color;
|
||||
this.save();
|
||||
}
|
||||
createSpritePart(sprite: string): SpritePart {
|
||||
return {
|
||||
type: 'sprite',
|
||||
sprite,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
}
|
||||
createBoundsPart(type: any): CoverPart {
|
||||
return {
|
||||
type,
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 10,
|
||||
h: 10,
|
||||
};
|
||||
}
|
||||
createPart(type: string): Part {
|
||||
switch (type) {
|
||||
case 'sprite':
|
||||
return this.createSpritePart('apple');
|
||||
case 'cover':
|
||||
case 'collider':
|
||||
return this.createBoundsPart(type);
|
||||
case 'pickable':
|
||||
return { type, x: 0, y: 0 };
|
||||
default:
|
||||
throw new Error(`Invalid type (${type})`);
|
||||
}
|
||||
}
|
||||
addPart(type: string) {
|
||||
this.parts.push(this.createPart(type));
|
||||
this.changed();
|
||||
}
|
||||
removePart(part: Part) {
|
||||
removeItem(this.parts, part);
|
||||
this.changed();
|
||||
}
|
||||
centerPart(part: Part) {
|
||||
if (part.type === 'sprite') {
|
||||
const sprite = getSprite(part.sprite);
|
||||
const color = sprite && sprite.color;
|
||||
|
||||
if (color) {
|
||||
part.x = Math.round(-color.ox - color.w / 2);
|
||||
part.y = Math.round(-color.oy - color.h / 2);
|
||||
}
|
||||
}
|
||||
if (color) {
|
||||
part.x = Math.round(-color.ox - color.w / 2);
|
||||
part.y = Math.round(-color.oy - color.h / 2);
|
||||
}
|
||||
}
|
||||
|
||||
this.changed();
|
||||
}
|
||||
private save() {
|
||||
this.storage.setJSON('tools-entity', <EntityData>{
|
||||
parts: this.parts,
|
||||
entities: this.entities,
|
||||
});
|
||||
}
|
||||
private load() {
|
||||
return this.storage.getJSON<EntityData>('tools-entity', {});
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
private save() {
|
||||
this.storage.setJSON('tools-entity', <EntityData>{
|
||||
parts: this.parts,
|
||||
entities: this.entities,
|
||||
});
|
||||
}
|
||||
private load() {
|
||||
return this.storage.getJSON<EntityData>('tools-entity', {});
|
||||
}
|
||||
}
|
||||
|
||||
function getBounds(part: Part): Rect | undefined {
|
||||
if (part.type === 'sprite') {
|
||||
const sprite = getSprite(part.sprite);
|
||||
const color = sprite && sprite.color;
|
||||
if (part.type === 'sprite') {
|
||||
const sprite = getSprite(part.sprite);
|
||||
const color = sprite && sprite.color;
|
||||
|
||||
if (color) {
|
||||
return {
|
||||
x: part.x + color.ox,
|
||||
y: part.y + color.oy,
|
||||
w: color.w,
|
||||
h: color.h,
|
||||
};
|
||||
}
|
||||
} else if (part.type === 'cover' || part.type === 'collider') {
|
||||
return part;
|
||||
}
|
||||
if (color) {
|
||||
return {
|
||||
x: part.x + color.ox,
|
||||
y: part.y + color.oy,
|
||||
w: color.w,
|
||||
h: color.h,
|
||||
};
|
||||
}
|
||||
} else if (part.type === 'cover' || part.type === 'collider') {
|
||||
return part;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getSprite(name: string): PaletteRenderable {
|
||||
return (sprites as any)[name];
|
||||
return (sprites as any)[name];
|
||||
}
|
||||
|
||||
function drawSpritePart(batch: PaletteSpriteBatch, part: SpritePart, px: number, py: number) {
|
||||
const sprite = getSprite(part.sprite);
|
||||
const sprite = getSprite(part.sprite);
|
||||
|
||||
if (!sprite)
|
||||
return;
|
||||
if (!sprite)
|
||||
return;
|
||||
|
||||
const x = px + part.x;
|
||||
const y = py + part.y;
|
||||
const palette = paletteManager.addArray(sprite.palettes![0]);
|
||||
const x = px + part.x;
|
||||
const y = py + part.y;
|
||||
const palette = paletteManager.addArray(sprite.palettes![0]);
|
||||
|
||||
sprite.shadow && batch.drawSprite(sprite.shadow, SHADOW_COLOR, defaultPalette, x, y);
|
||||
sprite.color && batch.drawSprite(sprite.color, WHITE, palette, x, y);
|
||||
sprite.shadow && batch.drawSprite(sprite.shadow, SHADOW_COLOR, defaultPalette, x, y);
|
||||
sprite.color && batch.drawSprite(sprite.color, WHITE, palette, x, y);
|
||||
|
||||
releasePalette(palette);
|
||||
releasePalette(palette);
|
||||
}
|
||||
|
||||
function drawPart(batch: PaletteSpriteBatch, part: Part, x: number, y: number) {
|
||||
if (part.type === 'sprite') {
|
||||
return drawSpritePart(batch, part, x, y);
|
||||
} else if (part.type === 'cover' || part.type === 'collider') {
|
||||
return drawOutline(batch, colors[part.type], part.x + x, part.y + y, part.w, part.h);
|
||||
} else if (part.type === 'pickable') {
|
||||
return drawOutline(batch, colors[part.type], part.x + x, part.y + y, 1, 1);
|
||||
} else {
|
||||
throw new Error(`Invalid part type (${(part as any).type})`);
|
||||
}
|
||||
if (part.type === 'sprite') {
|
||||
return drawSpritePart(batch, part, x, y);
|
||||
} else if (part.type === 'cover' || part.type === 'collider') {
|
||||
return drawOutline(batch, colors[part.type], part.x + x, part.y + y, part.w, part.h);
|
||||
} else if (part.type === 'pickable') {
|
||||
return drawOutline(batch, colors[part.type], part.x + x, part.y + y, 1, 1);
|
||||
} else {
|
||||
throw new Error(`Invalid part type (${(part as any).type})`);
|
||||
}
|
||||
}
|
||||
|
||||
function drawBufferScaled(canvas: HTMLCanvasElement, buffer: HTMLCanvasElement, scale: number) {
|
||||
const context = canvas.getContext('2d')!;
|
||||
context.save();
|
||||
disableImageSmoothing(context);
|
||||
context.scale(scale, scale);
|
||||
context.drawImage(buffer, 0, 0);
|
||||
context.restore();
|
||||
const context = canvas.getContext('2d')!;
|
||||
context.save();
|
||||
disableImageSmoothing(context);
|
||||
context.scale(scale, scale);
|
||||
context.drawImage(buffer, 0, 0);
|
||||
context.restore();
|
||||
}
|
||||
|
||||
function drawMixin(sprite: PaletteRenderable, dx: number, dy: number, paletteIndex = 0): EntityPart {
|
||||
const bounds = getRenderableBounds(sprite, dx, dy);
|
||||
const bounds = getRenderableBounds(sprite, dx, dy);
|
||||
|
||||
if (SERVER && !TESTS)
|
||||
return { bounds };
|
||||
if (SERVER && !TESTS)
|
||||
return { bounds };
|
||||
|
||||
const defaultPalette = sprite.shadow && createPalette(sprites.defaultPalette);
|
||||
const palette = createPalette(att(sprite.palettes, paletteIndex));
|
||||
const defaultPalette = sprite.shadow && createPalette(sprites.defaultPalette);
|
||||
const palette = createPalette(att(sprite.palettes, paletteIndex));
|
||||
|
||||
return {
|
||||
bounds,
|
||||
draw(this: Entity, batch: PaletteSpriteBatch, options: DrawOptions) {
|
||||
const x = toScreenX(this.x + (this.ox || 0)) - dx;
|
||||
const y = toScreenYWithZ(this.y + (this.oy || 0), this.z + (this.oz || 0)) - dy;
|
||||
const opacity = 1 - 0.6 * (this.coverLifting || 0);
|
||||
return {
|
||||
bounds,
|
||||
draw(this: Entity, batch: PaletteSpriteBatch, options: DrawOptions) {
|
||||
const x = toScreenX(this.x + (this.ox || 0)) - dx;
|
||||
const y = toScreenYWithZ(this.y + (this.oy || 0), this.z + (this.oz || 0)) - dy;
|
||||
const opacity = 1 - 0.6 * (this.coverLifting || 0);
|
||||
|
||||
if (sprite.shadow !== undefined) {
|
||||
batch.drawSprite(sprite.shadow, options.shadowColor, defaultPalette, x, y);
|
||||
}
|
||||
if (sprite.shadow !== undefined) {
|
||||
batch.drawSprite(sprite.shadow, options.shadowColor, defaultPalette, x, y);
|
||||
}
|
||||
|
||||
batch.globalAlpha = opacity;
|
||||
batch.globalAlpha = opacity;
|
||||
|
||||
if (sprite.color !== undefined) {
|
||||
batch.drawSprite(sprite.color, WHITE, palette, x, y);
|
||||
}
|
||||
if (sprite.color !== undefined) {
|
||||
batch.drawSprite(sprite.color, WHITE, palette, x, y);
|
||||
}
|
||||
|
||||
batch.globalAlpha = 1;
|
||||
},
|
||||
palettes: compact([defaultPalette, palette]),
|
||||
};
|
||||
batch.globalAlpha = 1;
|
||||
},
|
||||
palettes: compact([defaultPalette, palette]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,95 +13,95 @@ import { faHome } from '../../../client/icons';
|
||||
import { paletteSpriteSheet } from '../../../generated/sprites';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-expressions',
|
||||
templateUrl: 'tools-expressions.pug',
|
||||
selector: 'tools-expressions',
|
||||
templateUrl: 'tools-expressions.pug',
|
||||
})
|
||||
export class ToolsExpressions implements OnInit {
|
||||
readonly homeIcon = faHome;
|
||||
scale = 2;
|
||||
columns = 12;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
constructor() {
|
||||
}
|
||||
ngOnInit() {
|
||||
loadAndInitSpriteSheets()
|
||||
.then(() => this.redraw());
|
||||
}
|
||||
redraw() {
|
||||
this.draw();
|
||||
}
|
||||
png() {
|
||||
this.draw();
|
||||
saveCanvas(this.canvas.nativeElement, 'expressions.png');
|
||||
}
|
||||
private draw() {
|
||||
drawSheet(this.canvas.nativeElement, this.scale, this.columns);
|
||||
}
|
||||
readonly homeIcon = faHome;
|
||||
scale = 2;
|
||||
columns = 12;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
constructor() {
|
||||
}
|
||||
ngOnInit() {
|
||||
loadAndInitSpriteSheets()
|
||||
.then(() => this.redraw());
|
||||
}
|
||||
redraw() {
|
||||
this.draw();
|
||||
}
|
||||
png() {
|
||||
this.draw();
|
||||
saveCanvas(this.canvas.nativeElement, 'expressions.png');
|
||||
}
|
||||
private draw() {
|
||||
drawSheet(this.canvas.nativeElement, this.scale, this.columns);
|
||||
}
|
||||
}
|
||||
|
||||
function drawSheet(canvas: HTMLCanvasElement, scale: number, columns: number, bg = 'lightgreen'): HTMLCanvasElement {
|
||||
const frameWidth = 55;
|
||||
const frameOffset = 50;
|
||||
const frameHeight = 30;
|
||||
const buffer = createCanvas(frameWidth, frameHeight);
|
||||
const batch = new ContextSpriteBatch(buffer);
|
||||
const pony = createPony();
|
||||
const state = createState();
|
||||
const info = toPalette(pony);
|
||||
const filteredExpressions = expressions.filter(([, expr]) => !!expr).slice(2);
|
||||
const rows = Math.ceil(filteredExpressions.length / columns);
|
||||
const options = defaultDrawPonyOptions();
|
||||
const frameWidth = 55;
|
||||
const frameOffset = 50;
|
||||
const frameHeight = 30;
|
||||
const buffer = createCanvas(frameWidth, frameHeight);
|
||||
const batch = new ContextSpriteBatch(buffer);
|
||||
const pony = createPony();
|
||||
const state = createState();
|
||||
const info = toPalette(pony);
|
||||
const filteredExpressions = expressions.filter(([, expr]) => !!expr).slice(2);
|
||||
const rows = Math.ceil(filteredExpressions.length / columns);
|
||||
const options = defaultDrawPonyOptions();
|
||||
|
||||
canvas.width = ((frameOffset * (columns - 1)) + frameWidth) * scale;
|
||||
canvas.height = (frameHeight * rows) * scale;
|
||||
canvas.width = ((frameOffset * (columns - 1)) + frameWidth) * scale;
|
||||
canvas.height = (frameHeight * rows) * scale;
|
||||
|
||||
const viewContext = canvas.getContext('2d')!;
|
||||
viewContext.save();
|
||||
disableImageSmoothing(viewContext);
|
||||
viewContext.scale(scale, scale);
|
||||
const viewContext = canvas.getContext('2d')!;
|
||||
viewContext.save();
|
||||
disableImageSmoothing(viewContext);
|
||||
viewContext.scale(scale, scale);
|
||||
|
||||
if (bg) {
|
||||
viewContext.fillStyle = bg;
|
||||
viewContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
if (bg) {
|
||||
viewContext.fillStyle = bg;
|
||||
viewContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
viewContext.font = 'normal 6px monospace';
|
||||
viewContext.textAlign = 'right';
|
||||
viewContext.fillStyle = 'black';
|
||||
viewContext.font = 'normal 6px monospace';
|
||||
viewContext.textAlign = 'right';
|
||||
viewContext.fillStyle = 'black';
|
||||
|
||||
filteredExpressions.forEach(([name, [right, left, muzzle, rightIris = 0, leftIris = 0, extra = 0]]: any, i) => {
|
||||
state.expression = { right, left, muzzle, rightIris, leftIris, extra };
|
||||
filteredExpressions.forEach(([name, [right, left, muzzle, rightIris = 0, leftIris = 0, extra = 0]]: any, i) => {
|
||||
state.expression = { right, left, muzzle, rightIris, leftIris, extra };
|
||||
|
||||
batch.start(paletteSpriteSheet, 0);
|
||||
drawPony(batch, info, state, 35, 50, options);
|
||||
batch.end();
|
||||
batch.start(paletteSpriteSheet, 0);
|
||||
drawPony(batch, info, state, 35, 50, options);
|
||||
batch.end();
|
||||
|
||||
const x = (i % columns) * frameOffset;
|
||||
const y = Math.floor(i / columns) * frameHeight;
|
||||
const x = (i % columns) * frameOffset;
|
||||
const y = Math.floor(i / columns) * frameHeight;
|
||||
|
||||
viewContext.drawImage(buffer, x, y);
|
||||
viewContext.fillText(name, x + 18, y + 20);
|
||||
});
|
||||
viewContext.drawImage(buffer, x, y);
|
||||
viewContext.fillText(name, x + 18, y + 20);
|
||||
});
|
||||
|
||||
viewContext.restore();
|
||||
return canvas;
|
||||
viewContext.restore();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function createState(): PonyState {
|
||||
const state = defaultPonyState();
|
||||
state.blushColor = RED;
|
||||
state.animation = createBodyAnimation('', 24, false, [[0, 1]]);
|
||||
return state;
|
||||
const state = defaultPonyState();
|
||||
state.blushColor = RED;
|
||||
state.animation = createBodyAnimation('', 24, false, [[0, 1]]);
|
||||
return state;
|
||||
}
|
||||
|
||||
function createPony(): PonyInfo {
|
||||
const pony = createDefaultPony();
|
||||
pony.mane!.type = 0;
|
||||
pony.backMane!.type = 0;
|
||||
pony.tail!.type = 0;
|
||||
pony.coatFill = 'dec078';
|
||||
pony.lockCoatOutline = true;
|
||||
pony.lockBackLegAccessory = false;
|
||||
pony.eyeColorRight = 'cornflowerblue';
|
||||
return syncLockedPonyInfo(pony);
|
||||
const pony = createDefaultPony();
|
||||
pony.mane!.type = 0;
|
||||
pony.backMane!.type = 0;
|
||||
pony.tail!.type = 0;
|
||||
pony.coatFill = 'dec078';
|
||||
pony.lockCoatOutline = true;
|
||||
pony.lockBackLegAccessory = false;
|
||||
pony.eyeColorRight = 'cornflowerblue';
|
||||
return syncLockedPonyInfo(pony);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-index',
|
||||
templateUrl: 'tools-index.pug',
|
||||
selector: 'tools-index',
|
||||
templateUrl: 'tools-index.pug',
|
||||
})
|
||||
export class ToolsIndex {
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { tileHeight, tileWidth, REGION_SIZE } from '../../../common/constants';
|
||||
import { faHome } from '../../../client/icons';
|
||||
import { updateMap, getTile, createWorldMap, setRegion, setTile } from '../../../common/worldMap';
|
||||
import {
|
||||
Season, DrawOptions, defaultDrawOptions, EntityFlags, Entity, WorldMap, defaultWorldState, MapType, MapFlags
|
||||
Season, DrawOptions, defaultDrawOptions, EntityFlags, Entity, WorldMap, defaultWorldState, MapType, MapFlags
|
||||
} from '../../../common/interfaces';
|
||||
import { drawCanvas } from '../../../graphics/contextSpriteBatch';
|
||||
import { paletteSpriteSheet } from '../../../generated/sprites';
|
||||
@@ -17,7 +17,7 @@ import { createCamera } from '../../../common/camera';
|
||||
import { mockPaletteManager } from '../../../common/ponyInfo';
|
||||
import { isCritter } from '../../../common/entityUtils';
|
||||
import {
|
||||
createAnEntity, cloud, pony, apple, apple2, orange, orange2, candy, gift1, gift2, appleGreen, appleGreen2
|
||||
createAnEntity, cloud, pony, apple, apple2, orange, orange2, candy, gift1, gift2, appleGreen, appleGreen2
|
||||
} from '../../../common/entities';
|
||||
import { drawMap } from '../../../client/draw';
|
||||
import { includes, observableToPromise, hasFlag } from '../../../common/utils';
|
||||
@@ -27,184 +27,184 @@ import { getTileColor } from '../../../common/colors';
|
||||
import { colorToCSS } from '../../../common/color';
|
||||
|
||||
export interface ToolsMapOtherInfo {
|
||||
season: Season;
|
||||
entities: { type: number; x: number; y: number; order: number; id: number; }[];
|
||||
season: Season;
|
||||
entities: { type: number; x: number; y: number; order: number; id: number; }[];
|
||||
}
|
||||
|
||||
export interface ToolsMapInfo {
|
||||
width: number;
|
||||
height: number;
|
||||
defaultTile: number;
|
||||
tiles?: string;
|
||||
type: MapType;
|
||||
info: ToolsMapOtherInfo;
|
||||
width: number;
|
||||
height: number;
|
||||
defaultTile: number;
|
||||
tiles?: string;
|
||||
type: MapType;
|
||||
info: ToolsMapOtherInfo;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tools-map',
|
||||
templateUrl: 'tools-map.pug',
|
||||
selector: 'tools-map',
|
||||
templateUrl: 'tools-map.pug',
|
||||
})
|
||||
export class ToolsMap implements OnInit {
|
||||
readonly homeIcon = faHome;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
maps: string[] = [];
|
||||
selectedMap = '';
|
||||
grid = false;
|
||||
private map?: WorldMap;
|
||||
private info?: ToolsMapOtherInfo;
|
||||
constructor(private http: HttpClient, private storage: StorageService) {
|
||||
}
|
||||
get scale() {
|
||||
return this.storage.getInt('tools-map-scale') || 1;
|
||||
}
|
||||
set scale(value) {
|
||||
this.storage.setInt('tools-map-scale', value);
|
||||
}
|
||||
get type() {
|
||||
return this.storage.getItem('tools-map-type') || 'regular';
|
||||
}
|
||||
set type(value) {
|
||||
this.storage.setItem('tools-map-type', value);
|
||||
}
|
||||
async ngOnInit() {
|
||||
await loadAndInitSpriteSheets();
|
||||
await this.fetchList();
|
||||
await this.fetch();
|
||||
}
|
||||
setType(type: string) {
|
||||
this.type = type;
|
||||
this.redraw();
|
||||
}
|
||||
async fetchList() {
|
||||
this.maps = await observableToPromise(this.http.get<string[]>('/api-tools/maps'));
|
||||
}
|
||||
fetch() {
|
||||
this.http.get<ToolsMapInfo>('/api-tools/map', { params: { map: this.selectedMap } }).subscribe(map => {
|
||||
this.info = map.info;
|
||||
readonly homeIcon = faHome;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
maps: string[] = [];
|
||||
selectedMap = '';
|
||||
grid = false;
|
||||
private map?: WorldMap;
|
||||
private info?: ToolsMapOtherInfo;
|
||||
constructor(private http: HttpClient, private storage: StorageService) {
|
||||
}
|
||||
get scale() {
|
||||
return this.storage.getInt('tools-map-scale') || 1;
|
||||
}
|
||||
set scale(value) {
|
||||
this.storage.setInt('tools-map-scale', value);
|
||||
}
|
||||
get type() {
|
||||
return this.storage.getItem('tools-map-type') || 'regular';
|
||||
}
|
||||
set type(value) {
|
||||
this.storage.setItem('tools-map-type', value);
|
||||
}
|
||||
async ngOnInit() {
|
||||
await loadAndInitSpriteSheets();
|
||||
await this.fetchList();
|
||||
await this.fetch();
|
||||
}
|
||||
setType(type: string) {
|
||||
this.type = type;
|
||||
this.redraw();
|
||||
}
|
||||
async fetchList() {
|
||||
this.maps = await observableToPromise(this.http.get<string[]>('/api-tools/maps'));
|
||||
}
|
||||
fetch() {
|
||||
this.http.get<ToolsMapInfo>('/api-tools/map', { params: { map: this.selectedMap } }).subscribe(map => {
|
||||
this.info = map.info;
|
||||
|
||||
const regionsX = map.width / REGION_SIZE;
|
||||
const regionsY = map.height / REGION_SIZE;
|
||||
const { type, defaultTile } = map;
|
||||
const regionsX = map.width / REGION_SIZE;
|
||||
const regionsY = map.height / REGION_SIZE;
|
||||
const { type, defaultTile } = map;
|
||||
|
||||
this.map = createWorldMap({ type, flags: MapFlags.None, defaultTile, regionsX, regionsY });
|
||||
const tiles = deserializeTiles(map.tiles!);
|
||||
this.map = createWorldMap({ type, flags: MapFlags.None, defaultTile, regionsX, regionsY });
|
||||
const tiles = deserializeTiles(map.tiles!);
|
||||
|
||||
for (let y = 0, i = 0; y < regionsX; y++) {
|
||||
for (let x = 0; x < regionsY; x++ , i++) {
|
||||
setRegion(this.map, x, y, createRegion(x, y));
|
||||
}
|
||||
}
|
||||
for (let y = 0, i = 0; y < regionsX; y++) {
|
||||
for (let x = 0; x < regionsY; x++ , i++) {
|
||||
setRegion(this.map, x, y, createRegion(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
for (let y = 0, i = 0; y < map.height; y++) {
|
||||
for (let x = 0; x < map.width; x++ , i++) {
|
||||
setTile(this.map, x, y, tiles[i]);
|
||||
}
|
||||
}
|
||||
for (let y = 0, i = 0; y < map.height; y++) {
|
||||
for (let x = 0; x < map.width; x++ , i++) {
|
||||
setTile(this.map, x, y, tiles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.redraw();
|
||||
});
|
||||
}
|
||||
selectMap(map: string) {
|
||||
this.selectedMap = map;
|
||||
this.fetch();
|
||||
}
|
||||
redraw() {
|
||||
this.draw();
|
||||
}
|
||||
png() {
|
||||
saveCanvas(this.canvas.nativeElement, 'map.png');
|
||||
}
|
||||
private draw() {
|
||||
if (this.map && this.info) {
|
||||
if (this.type === 'regular') {
|
||||
drawTheMap(this.canvas.nativeElement, this.map, this.info, this.scale, this.grid);
|
||||
} else if (this.type === 'minimap') {
|
||||
drawMinimap(this.canvas.nativeElement, this.map, this.info, this.scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.redraw();
|
||||
});
|
||||
}
|
||||
selectMap(map: string) {
|
||||
this.selectedMap = map;
|
||||
this.fetch();
|
||||
}
|
||||
redraw() {
|
||||
this.draw();
|
||||
}
|
||||
png() {
|
||||
saveCanvas(this.canvas.nativeElement, 'map.png');
|
||||
}
|
||||
private draw() {
|
||||
if (this.map && this.info) {
|
||||
if (this.type === 'regular') {
|
||||
drawTheMap(this.canvas.nativeElement, this.map, this.info, this.scale, this.grid);
|
||||
} else if (this.type === 'minimap') {
|
||||
drawMinimap(this.canvas.nativeElement, this.map, this.info, this.scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawTheMap(canvas: HTMLCanvasElement, map: WorldMap, info: ToolsMapOtherInfo, scale: number, grid: boolean) {
|
||||
const mapCanvas = drawCanvas(map.width * tileWidth, map.height * tileHeight, paletteSpriteSheet, 0x222222ff, batch => {
|
||||
const camera = createCamera();
|
||||
camera.w = map.width * tileWidth;
|
||||
camera.h = map.height * tileHeight;
|
||||
const mapCanvas = drawCanvas(map.width * tileWidth, map.height * tileHeight, paletteSpriteSheet, 0x222222ff, batch => {
|
||||
const camera = createCamera();
|
||||
camera.w = map.width * tileWidth;
|
||||
camera.h = map.height * tileHeight;
|
||||
|
||||
const tileSets = createTileSets(mockPaletteManager, info.season, map.type);
|
||||
const lightData = createLightData(info.season);
|
||||
const tileSets = createTileSets(mockPaletteManager, info.season, map.type);
|
||||
const lightData = createLightData(info.season);
|
||||
|
||||
const drawOptions: DrawOptions = {
|
||||
...defaultDrawOptions,
|
||||
tileGrid: grid,
|
||||
shadowColor: getShadowColor(lightData, HOUR_LENGTH * 12),
|
||||
};
|
||||
const drawOptions: DrawOptions = {
|
||||
...defaultDrawOptions,
|
||||
tileGrid: grid,
|
||||
shadowColor: getShadowColor(lightData, HOUR_LENGTH * 12),
|
||||
};
|
||||
|
||||
const ignoreTypes = [
|
||||
cloud, pony, apple, apple2, appleGreen, appleGreen2, orange, orange2, candy, gift1, gift2
|
||||
].map(e => e.type);
|
||||
const ignoreTypes = [
|
||||
cloud, pony, apple, apple2, appleGreen, appleGreen2, orange, orange2, candy, gift1, gift2
|
||||
].map(e => e.type);
|
||||
|
||||
const shouldDraw = (e: Entity) => {
|
||||
return !hasFlag(e.flags, EntityFlags.Debug) && !isCritter(e) && !includes(ignoreTypes, e.type);
|
||||
};
|
||||
const shouldDraw = (e: Entity) => {
|
||||
return !hasFlag(e.flags, EntityFlags.Debug) && !isCritter(e) && !includes(ignoreTypes, e.type);
|
||||
};
|
||||
|
||||
map.entitiesDrawable = info.entities
|
||||
.map(({ type, id, x, y }) => createAnEntity(type, id, x, y, {}, mockPaletteManager, defaultWorldState))
|
||||
.filter(shouldDraw);
|
||||
map.entitiesDrawable = info.entities
|
||||
.map(({ type, id, x, y }) => createAnEntity(type, id, x, y, {}, mockPaletteManager, defaultWorldState))
|
||||
.filter(shouldDraw);
|
||||
|
||||
updateMap(map, 0);
|
||||
drawMap(batch, map, camera, {} as any, drawOptions, tileSets, []);
|
||||
});
|
||||
updateMap(map, 0);
|
||||
drawMap(batch, map, camera, {} as any, drawOptions, tileSets, []);
|
||||
});
|
||||
|
||||
canvas.width = Math.floor(mapCanvas.width / scale);
|
||||
canvas.height = Math.floor(mapCanvas.height / scale);
|
||||
const context = canvas.getContext('2d')!;
|
||||
// disableImageSmoothing(context);
|
||||
context.scale(1 / scale, 1 / scale);
|
||||
context.drawImage(mapCanvas, 0, 0);
|
||||
canvas.width = Math.floor(mapCanvas.width / scale);
|
||||
canvas.height = Math.floor(mapCanvas.height / scale);
|
||||
const context = canvas.getContext('2d')!;
|
||||
// disableImageSmoothing(context);
|
||||
context.scale(1 / scale, 1 / scale);
|
||||
context.drawImage(mapCanvas, 0, 0);
|
||||
}
|
||||
|
||||
function drawMinimap(canvas: HTMLCanvasElement, map: WorldMap, info: ToolsMapOtherInfo, scale: number) {
|
||||
const tileWidth = 1;
|
||||
const tileHeight = 1;
|
||||
const tileWidth = 1;
|
||||
const tileHeight = 1;
|
||||
|
||||
const mapCanvas = createCanvas(map.width * tileWidth, map.height * tileHeight);
|
||||
const mapContext = mapCanvas.getContext('2d')!;
|
||||
const mapCanvas = createCanvas(map.width * tileWidth, map.height * tileHeight);
|
||||
const mapContext = mapCanvas.getContext('2d')!;
|
||||
|
||||
updateMap(map, 0);
|
||||
updateMap(map, 0);
|
||||
|
||||
for (let x = 0; x < map.width; x++) {
|
||||
for (let y = 0; y < map.height; y++) {
|
||||
const tile = getTile(map, x, y);
|
||||
const color = getTileColor(tile, info.season);
|
||||
mapContext.fillStyle = colorToCSS(color);
|
||||
mapContext.fillRect(x, y, 1, 1);
|
||||
}
|
||||
}
|
||||
for (let x = 0; x < map.width; x++) {
|
||||
for (let y = 0; y < map.height; y++) {
|
||||
const tile = getTile(map, x, y);
|
||||
const color = getTileColor(tile, info.season);
|
||||
mapContext.fillStyle = colorToCSS(color);
|
||||
mapContext.fillRect(x, y, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
map.entities = info.entities
|
||||
.map(({ type, id, x, y }) => createAnEntity(type, id, x, y, {}, mockPaletteManager, defaultWorldState));
|
||||
map.entities = info.entities
|
||||
.map(({ type, id, x, y }) => createAnEntity(type, id, x, y, {}, mockPaletteManager, defaultWorldState));
|
||||
|
||||
for (let i = 1; i <= 2; i++) {
|
||||
for (const e of map.entities) {
|
||||
if (e.minimap && e.minimap.order === i) {
|
||||
const { color, rect } = e.minimap;
|
||||
mapContext.fillStyle = colorToCSS(color);
|
||||
mapContext.fillRect(Math.round(e.x + rect.x), Math.round(e.y + rect.y), rect.w, rect.h);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 1; i <= 2; i++) {
|
||||
for (const e of map.entities) {
|
||||
if (e.minimap && e.minimap.order === i) {
|
||||
const { color, rect } = e.minimap;
|
||||
mapContext.fillStyle = colorToCSS(color);
|
||||
mapContext.fillRect(Math.round(e.x + rect.x), Math.round(e.y + rect.y), rect.w, rect.h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = mapCanvas.width * scale;
|
||||
canvas.height = mapCanvas.height * scale;
|
||||
const context = canvas.getContext('2d')!;
|
||||
context.save();
|
||||
canvas.width = mapCanvas.width * scale;
|
||||
canvas.height = mapCanvas.height * scale;
|
||||
const context = canvas.getContext('2d')!;
|
||||
context.save();
|
||||
|
||||
if (scale >= 1) {
|
||||
disableImageSmoothing(context);
|
||||
}
|
||||
if (scale >= 1) {
|
||||
disableImageSmoothing(context);
|
||||
}
|
||||
|
||||
context.scale(scale, scale);
|
||||
context.drawImage(mapCanvas, 0, 0);
|
||||
context.restore();
|
||||
context.scale(scale, scale);
|
||||
context.drawImage(mapCanvas, 0, 0);
|
||||
context.restore();
|
||||
}
|
||||
|
||||
@@ -16,63 +16,63 @@ const paletteManager = new PaletteManager();
|
||||
const defaultPalette = paletteManager.add(DEFAULT_PALETTE);
|
||||
|
||||
@Component({
|
||||
selector: 'tools-palette',
|
||||
templateUrl: 'tools-palette.pug',
|
||||
selector: 'tools-palette',
|
||||
templateUrl: 'tools-palette.pug',
|
||||
})
|
||||
export class ToolsPalette implements OnInit {
|
||||
readonly homeIcon = faHome;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
scale = 3;
|
||||
sprites = Object.keys(sprites).filter(key => {
|
||||
const s = (sprites as any)[key] as any;
|
||||
return !!(s && s.color);
|
||||
});
|
||||
spriteName = '';
|
||||
palette = ['red', 'blue', 'orange', 'violet'].map(x => ({ original: x, current: x }));
|
||||
ngOnInit() {
|
||||
setPaletteManager(paletteManager);
|
||||
loadAndInitSpriteSheets().then(() => this.redraw());
|
||||
}
|
||||
spriteChanged() {
|
||||
this.redraw();
|
||||
}
|
||||
loadPalette() {
|
||||
const sprite = (sprites as any)[this.spriteName] as PaletteRenderable;
|
||||
readonly homeIcon = faHome;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
scale = 3;
|
||||
sprites = Object.keys(sprites).filter(key => {
|
||||
const s = (sprites as any)[key] as any;
|
||||
return !!(s && s.color);
|
||||
});
|
||||
spriteName = '';
|
||||
palette = ['red', 'blue', 'orange', 'violet'].map(x => ({ original: x, current: x }));
|
||||
ngOnInit() {
|
||||
setPaletteManager(paletteManager);
|
||||
loadAndInitSpriteSheets().then(() => this.redraw());
|
||||
}
|
||||
spriteChanged() {
|
||||
this.redraw();
|
||||
}
|
||||
loadPalette() {
|
||||
const sprite = (sprites as any)[this.spriteName] as PaletteRenderable;
|
||||
|
||||
if (sprite) {
|
||||
this.palette = Array.from(sprite.palettes![0]).map(colorToCSS).map(c => ({ original: c, current: c }));
|
||||
}
|
||||
if (sprite) {
|
||||
this.palette = Array.from(sprite.palettes![0]).map(colorToCSS).map(c => ({ original: c, current: c }));
|
||||
}
|
||||
|
||||
this.redraw();
|
||||
}
|
||||
redraw() {
|
||||
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
|
||||
const width = Math.ceil(canvas.width / this.scale);
|
||||
const height = Math.ceil(canvas.height / this.scale);
|
||||
this.redraw();
|
||||
}
|
||||
redraw() {
|
||||
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
|
||||
const width = Math.ceil(canvas.width / this.scale);
|
||||
const height = Math.ceil(canvas.height / this.scale);
|
||||
|
||||
const buffer = drawCanvas(width, height, sprites.paletteSpriteSheet, BG, batch => {
|
||||
const sprite = (sprites as any)[this.spriteName] as PaletteRenderable;
|
||||
const buffer = drawCanvas(width, height, sprites.paletteSpriteSheet, BG, batch => {
|
||||
const sprite = (sprites as any)[this.spriteName] as PaletteRenderable;
|
||||
|
||||
if (sprite) {
|
||||
const palette = paletteManager.add(this.palette.map(x => parseColor(x.current)));
|
||||
if (sprite) {
|
||||
const palette = paletteManager.add(this.palette.map(x => parseColor(x.current)));
|
||||
|
||||
const x = (width - (sprite.color!.w + sprite.color!.ox)) / 2;
|
||||
const y = (height - (sprite.color!.h + sprite.color!.oy)) / 2;
|
||||
const x = (width - (sprite.color!.w + sprite.color!.ox)) / 2;
|
||||
const y = (height - (sprite.color!.h + sprite.color!.oy)) / 2;
|
||||
|
||||
console.log(x, y, width, sprite.color!.w, sprite.color!.ox);
|
||||
console.log(x, y, width, sprite.color!.w, sprite.color!.ox);
|
||||
|
||||
batch.drawSprite(sprite.shadow, SHADOW_COLOR, defaultPalette, x, y);
|
||||
batch.drawSprite(sprite.color, WHITE, palette, x, y);
|
||||
batch.drawSprite(sprite.shadow, SHADOW_COLOR, defaultPalette, x, y);
|
||||
batch.drawSprite(sprite.color, WHITE, palette, x, y);
|
||||
|
||||
releasePalette(palette);
|
||||
}
|
||||
});
|
||||
releasePalette(palette);
|
||||
}
|
||||
});
|
||||
|
||||
const viewContext = canvas.getContext('2d')!;
|
||||
viewContext.save();
|
||||
disableImageSmoothing(viewContext);
|
||||
viewContext.scale(this.scale, this.scale);
|
||||
viewContext.drawImage(buffer, 0, 0);
|
||||
viewContext.restore();
|
||||
}
|
||||
const viewContext = canvas.getContext('2d')!;
|
||||
viewContext.save();
|
||||
disableImageSmoothing(viewContext);
|
||||
viewContext.scale(this.scale, this.scale);
|
||||
viewContext.drawImage(buffer, 0, 0);
|
||||
viewContext.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,156 +1,156 @@
|
||||
// import { TextEncoder } from 'util';
|
||||
|
||||
function forEachCharacter(value: string, callback: (code: number) => void) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const code = value.charCodeAt(i);
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const code = value.charCodeAt(i);
|
||||
|
||||
// high surrogate
|
||||
if (code >= 0xd800 && code <= 0xdbff) {
|
||||
if ((i + 1) < value.length) {
|
||||
const extra = value.charCodeAt(i + 1);
|
||||
// high surrogate
|
||||
if (code >= 0xd800 && code <= 0xdbff) {
|
||||
if ((i + 1) < value.length) {
|
||||
const extra = value.charCodeAt(i + 1);
|
||||
|
||||
// low surrogate
|
||||
if ((extra & 0xfc00) === 0xdc00) {
|
||||
i++;
|
||||
callback(((code & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callback(code);
|
||||
}
|
||||
}
|
||||
// low surrogate
|
||||
if ((extra & 0xfc00) === 0xdc00) {
|
||||
i++;
|
||||
callback(((code & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callback(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function charLengthInBytes(code: number): number {
|
||||
if ((code & 0xffffff80) === 0) {
|
||||
return 1;
|
||||
} else if ((code & 0xfffff800) === 0) {
|
||||
return 2;
|
||||
} else if ((code & 0xffff0000) === 0) {
|
||||
return 3;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
if ((code & 0xffffff80) === 0) {
|
||||
return 1;
|
||||
} else if ((code & 0xfffff800) === 0) {
|
||||
return 2;
|
||||
} else if ((code & 0xffff0000) === 0) {
|
||||
return 3;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
function stringLengthInBytes(value: string): number {
|
||||
let result = 0;
|
||||
forEachCharacter(value, code => result += charLengthInBytes(code));
|
||||
return result;
|
||||
let result = 0;
|
||||
forEachCharacter(value, code => result += charLengthInBytes(code));
|
||||
return result;
|
||||
}
|
||||
|
||||
function encodeStringTo(buffer: Uint8Array | Buffer, offset: number, value: string): number {
|
||||
forEachCharacter(value, code => {
|
||||
const length = charLengthInBytes(code);
|
||||
forEachCharacter(value, code => {
|
||||
const length = charLengthInBytes(code);
|
||||
|
||||
if (length === 1) {
|
||||
buffer[offset++] = code;
|
||||
} else {
|
||||
if (length === 2) {
|
||||
buffer[offset++] = ((code >> 6) & 0x1f) | 0xc0;
|
||||
} else if (length === 3) {
|
||||
buffer[offset++] = ((code >> 12) & 0x0f) | 0xe0;
|
||||
buffer[offset++] = ((code >> 6) & 0x3f) | 0x80;
|
||||
} else {
|
||||
buffer[offset++] = ((code >> 18) & 0x07) | 0xf0;
|
||||
buffer[offset++] = ((code >> 12) & 0x3f) | 0x80;
|
||||
buffer[offset++] = ((code >> 6) & 0x3f) | 0x80;
|
||||
}
|
||||
if (length === 1) {
|
||||
buffer[offset++] = code;
|
||||
} else {
|
||||
if (length === 2) {
|
||||
buffer[offset++] = ((code >> 6) & 0x1f) | 0xc0;
|
||||
} else if (length === 3) {
|
||||
buffer[offset++] = ((code >> 12) & 0x0f) | 0xe0;
|
||||
buffer[offset++] = ((code >> 6) & 0x3f) | 0x80;
|
||||
} else {
|
||||
buffer[offset++] = ((code >> 18) & 0x07) | 0xf0;
|
||||
buffer[offset++] = ((code >> 12) & 0x3f) | 0x80;
|
||||
buffer[offset++] = ((code >> 6) & 0x3f) | 0x80;
|
||||
}
|
||||
|
||||
buffer[offset++] = (code & 0x3f) | 0x80;
|
||||
}
|
||||
});
|
||||
buffer[offset++] = (code & 0x3f) | 0x80;
|
||||
}
|
||||
});
|
||||
|
||||
return offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
export function encodeString(value: string | null): Uint8Array | null {
|
||||
if (value == null)
|
||||
return null;
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
const buffer = new Uint8Array(stringLengthInBytes(value));
|
||||
encodeStringTo(buffer, 0, value);
|
||||
return buffer;
|
||||
const buffer = new Uint8Array(stringLengthInBytes(value));
|
||||
encodeStringTo(buffer, 0, value);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
export function encodeStringNew(value: string | null): Uint8Array | null {
|
||||
if (value == null)
|
||||
return null;
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
const buffer = new Uint8Array(stringLengthInBytes2(value));
|
||||
encodeStringTo2(buffer, 0, value);
|
||||
return buffer;
|
||||
const buffer = new Uint8Array(stringLengthInBytes2(value));
|
||||
encodeStringTo2(buffer, 0, value);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// new methods
|
||||
|
||||
function charLengthInBytes2(code: number): number {
|
||||
if ((code & 0xffffff80) === 0) {
|
||||
return 1;
|
||||
} else if ((code & 0xfffff800) === 0) {
|
||||
return 2;
|
||||
} else if ((code & 0xffff0000) === 0) {
|
||||
return 3;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
if ((code & 0xffffff80) === 0) {
|
||||
return 1;
|
||||
} else if ((code & 0xfffff800) === 0) {
|
||||
return 2;
|
||||
} else if ((code & 0xffff0000) === 0) {
|
||||
return 3;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
export function stringLengthInBytes2(value: string): number {
|
||||
let result = 0;
|
||||
forEachCharacter2(value, code => result = (result + charLengthInBytes2(code)) | 0);
|
||||
return result;
|
||||
let result = 0;
|
||||
forEachCharacter2(value, code => result = (result + charLengthInBytes2(code)) | 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function encodeStringTo2(buffer: Uint8Array, offset: number, value: string): number {
|
||||
forEachCharacter2(value, code => {
|
||||
const length = charLengthInBytes2(code) | 0;
|
||||
forEachCharacter2(value, code => {
|
||||
const length = charLengthInBytes2(code) | 0;
|
||||
|
||||
if (length === 1) {
|
||||
buffer[offset++] = code;
|
||||
} else {
|
||||
if (length === 2) {
|
||||
buffer[offset++] = ((code >> 6) & 0x1f) | 0xc0;
|
||||
} else if (length === 3) {
|
||||
buffer[offset++] = ((code >> 12) & 0x0f) | 0xe0;
|
||||
buffer[offset++] = ((code >> 6) & 0x3f) | 0x80;
|
||||
} else {
|
||||
buffer[offset++] = ((code >> 18) & 0x07) | 0xf0;
|
||||
buffer[offset++] = ((code >> 12) & 0x3f) | 0x80;
|
||||
buffer[offset++] = ((code >> 6) & 0x3f) | 0x80;
|
||||
}
|
||||
if (length === 1) {
|
||||
buffer[offset++] = code;
|
||||
} else {
|
||||
if (length === 2) {
|
||||
buffer[offset++] = ((code >> 6) & 0x1f) | 0xc0;
|
||||
} else if (length === 3) {
|
||||
buffer[offset++] = ((code >> 12) & 0x0f) | 0xe0;
|
||||
buffer[offset++] = ((code >> 6) & 0x3f) | 0x80;
|
||||
} else {
|
||||
buffer[offset++] = ((code >> 18) & 0x07) | 0xf0;
|
||||
buffer[offset++] = ((code >> 12) & 0x3f) | 0x80;
|
||||
buffer[offset++] = ((code >> 6) & 0x3f) | 0x80;
|
||||
}
|
||||
|
||||
buffer[offset++] = (code & 0x3f) | 0x80;
|
||||
}
|
||||
});
|
||||
buffer[offset++] = (code & 0x3f) | 0x80;
|
||||
}
|
||||
});
|
||||
|
||||
return offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
function forEachCharacter2(value: string, callback: (code: number) => void) {
|
||||
const length = value.length | 0;
|
||||
const lengthMinusOne = Math.max(0, length - 1) | 0;
|
||||
const length = value.length | 0;
|
||||
const lengthMinusOne = Math.max(0, length - 1) | 0;
|
||||
|
||||
for (let i = 0; i < length; i = (i + 1) | 0) {
|
||||
let code = value.charCodeAt(i) | 0;
|
||||
for (let i = 0; i < length; i = (i + 1) | 0) {
|
||||
let code = value.charCodeAt(i) | 0;
|
||||
|
||||
// high surrogate
|
||||
if (code >= 0xd800 && code <= 0xdbff) {
|
||||
if (i < lengthMinusOne) {
|
||||
const extra = value.charCodeAt(i + 1) | 0;
|
||||
// high surrogate
|
||||
if (code >= 0xd800 && code <= 0xdbff) {
|
||||
if (i < lengthMinusOne) {
|
||||
const extra = value.charCodeAt(i + 1) | 0;
|
||||
|
||||
// low surrogate
|
||||
if ((extra & 0xfc00) === 0xdc00) {
|
||||
i = (i + 1) | 0;
|
||||
code = (((((code & 0x3ff) << 10) + (extra & 0x3ff)) | 0) + 0x10000) | 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// low surrogate
|
||||
if ((extra & 0xfc00) === 0xdc00) {
|
||||
i = (i + 1) | 0;
|
||||
code = (((((code & 0x3ff) << 10) + (extra & 0x3ff)) | 0) + 0x10000) | 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
callback(code);
|
||||
}
|
||||
callback(code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,392 +13,392 @@ import { includes as utilsIncludes } from '../../../common/utils';
|
||||
import { encodeString, encodeStringNew } from './methods';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-perf',
|
||||
templateUrl: 'tools-perf.pug',
|
||||
selector: 'tools-perf',
|
||||
templateUrl: 'tools-perf.pug',
|
||||
})
|
||||
export class ToolsPerf {
|
||||
readonly homeIcon = faHome;
|
||||
output = '';
|
||||
ponies: string[] = [];
|
||||
messages: string[] = [];
|
||||
tests: { name: string; func: () => void; }[] = [];
|
||||
constructor(http: HttpClient, private zone: NgZone) {
|
||||
http.get<string[]>('/tests/ponies.json').subscribe(data => this.ponies = data);
|
||||
http.get<string[]>('/tests/messages.json').subscribe(data => this.messages = data);
|
||||
this.output = createPostDecompressPony().toString();
|
||||
this.tests.push({ name: 'arrays', func: () => this.runTest(arrayTest) });
|
||||
this.tests.push({ name: 'compress colors', func: () => this.runTest(compressColorsTest) });
|
||||
this.tests.push({ name: 'parse color', func: () => this.runTest(parseColorTest) });
|
||||
this.tests.push({ name: 'compare arrays', func: () => this.runTest(compareArrays) });
|
||||
this.tests.push({ name: 'utf', func: () => this.runTest(() => utfTest(this.messages)) });
|
||||
this.tests.push({ name: 'includes', func: () => this.runTest(includeTest) });
|
||||
}
|
||||
run() {
|
||||
this.runTest(() => utfTest(this.messages));
|
||||
}
|
||||
stats() {
|
||||
swearEntryTest(this.messages, x => this.output = x);
|
||||
}
|
||||
private runTest(test: () => void) {
|
||||
this.zone.runOutsideAngular(() => setTimeout(test, 20));
|
||||
}
|
||||
readonly homeIcon = faHome;
|
||||
output = '';
|
||||
ponies: string[] = [];
|
||||
messages: string[] = [];
|
||||
tests: { name: string; func: () => void; }[] = [];
|
||||
constructor(http: HttpClient, private zone: NgZone) {
|
||||
http.get<string[]>('/tests/ponies.json').subscribe(data => this.ponies = data);
|
||||
http.get<string[]>('/tests/messages.json').subscribe(data => this.messages = data);
|
||||
this.output = createPostDecompressPony().toString();
|
||||
this.tests.push({ name: 'arrays', func: () => this.runTest(arrayTest) });
|
||||
this.tests.push({ name: 'compress colors', func: () => this.runTest(compressColorsTest) });
|
||||
this.tests.push({ name: 'parse color', func: () => this.runTest(parseColorTest) });
|
||||
this.tests.push({ name: 'compare arrays', func: () => this.runTest(compareArrays) });
|
||||
this.tests.push({ name: 'utf', func: () => this.runTest(() => utfTest(this.messages)) });
|
||||
this.tests.push({ name: 'includes', func: () => this.runTest(includeTest) });
|
||||
}
|
||||
run() {
|
||||
this.runTest(() => utfTest(this.messages));
|
||||
}
|
||||
stats() {
|
||||
swearEntryTest(this.messages, x => this.output = x);
|
||||
}
|
||||
private runTest(test: () => void) {
|
||||
this.zone.runOutsideAngular(() => setTimeout(test, 20));
|
||||
}
|
||||
}
|
||||
|
||||
function measure(name: string, iterations: number, func: (i: number) => void) {
|
||||
if (!iterations)
|
||||
return;
|
||||
if (!iterations)
|
||||
return;
|
||||
|
||||
const start = performance.now();
|
||||
let v: any;
|
||||
const start = performance.now();
|
||||
let v: any;
|
||||
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
v = func(i);
|
||||
}
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
v = func(i);
|
||||
}
|
||||
|
||||
const end = performance.now();
|
||||
const diff = end - start;
|
||||
const end = performance.now();
|
||||
const diff = end - start;
|
||||
|
||||
console.log(`${name}: ${diff.toFixed(0)}ms, ${(diff / iterations).toFixed(3)}ms per iteration // ${!!v}`);
|
||||
console.log(`${name}: ${diff.toFixed(0)}ms, ${(diff / iterations).toFixed(3)}ms per iteration // ${!!v}`);
|
||||
}
|
||||
|
||||
export function compressColorsTest() {
|
||||
const colors = [
|
||||
3553475327, 2592097791, 3662487807, 545184511, 2744818431, 1658462463, 16764927, 7864319,
|
||||
4278253055, 2492366335, 10033407, 11763711, 6730751, 3003165951, 2997456127, 1447512063,
|
||||
1936281087, 874586623, 3713423103, 2099652351, 4293220607, 512819199, 852308735, 3664828159,
|
||||
3692313855, 2147472639, 2861699071, 5944319, 42992383, 2570622463, 2583699455, 1051954175,
|
||||
3013286911, 2762969343, 1400052223, 1991223551, 1049483775, 611346431, 272724223, 1392443647,
|
||||
1589395455, 3201321215, 2679322623, 3233857791, 1280068863, 2560137471, 437918463, 3908210943,
|
||||
3602601215, 4001558271, 2806294527, 2508550143, 1732985855, 1330597887, 1381126911, 1750746879,
|
||||
1211049983, 926365695, 960051711, 2659530751, 3597364223, 777334527, 2201321727, 2120247039,
|
||||
2441106175, 2354205439, 1844342271, 3613774847, 1967148031, 4289003775, 3600494335, 3164100095,
|
||||
2845275903, 3098517247, 1463486719, 1699355647, 1834628607, 1936084991, 2307095039, 857933311,
|
||||
740297471, 807801599, 740629247, 656811007, 3587560959, 2998055679, 2425393407, 1869574143,
|
||||
4294967295, 4294238719, 4293575679, 4292051711, 4291190527
|
||||
].map(x => x >>> 0);
|
||||
const colors = [
|
||||
3553475327, 2592097791, 3662487807, 545184511, 2744818431, 1658462463, 16764927, 7864319,
|
||||
4278253055, 2492366335, 10033407, 11763711, 6730751, 3003165951, 2997456127, 1447512063,
|
||||
1936281087, 874586623, 3713423103, 2099652351, 4293220607, 512819199, 852308735, 3664828159,
|
||||
3692313855, 2147472639, 2861699071, 5944319, 42992383, 2570622463, 2583699455, 1051954175,
|
||||
3013286911, 2762969343, 1400052223, 1991223551, 1049483775, 611346431, 272724223, 1392443647,
|
||||
1589395455, 3201321215, 2679322623, 3233857791, 1280068863, 2560137471, 437918463, 3908210943,
|
||||
3602601215, 4001558271, 2806294527, 2508550143, 1732985855, 1330597887, 1381126911, 1750746879,
|
||||
1211049983, 926365695, 960051711, 2659530751, 3597364223, 777334527, 2201321727, 2120247039,
|
||||
2441106175, 2354205439, 1844342271, 3613774847, 1967148031, 4289003775, 3600494335, 3164100095,
|
||||
2845275903, 3098517247, 1463486719, 1699355647, 1834628607, 1936084991, 2307095039, 857933311,
|
||||
740297471, 807801599, 740629247, 656811007, 3587560959, 2998055679, 2425393407, 1869574143,
|
||||
4294967295, 4294238719, 4293575679, 4292051711, 4291190527
|
||||
].map(x => x >>> 0);
|
||||
|
||||
const oldMethod = bitWriter(write => colors.forEach(x => write(x >> 8, 24)));
|
||||
const oldMethod = bitWriter(write => colors.forEach(x => write(x >> 8, 24)));
|
||||
|
||||
const truncated = colors.map(c => (c >>> 8) & 0xffffff);
|
||||
truncated.sort((a, b) => a > b ? 1 : (a < b ? -1 : 0));
|
||||
const truncated = colors.map(c => (c >>> 8) & 0xffffff);
|
||||
truncated.sort((a, b) => a > b ? 1 : (a < b ? -1 : 0));
|
||||
|
||||
console.log(truncated);
|
||||
console.log(truncated.slice(1).map((c, i) => (c - truncated[i]).toString(16)));
|
||||
console.log(truncated);
|
||||
console.log(truncated.slice(1).map((c, i) => (c - truncated[i]).toString(16)));
|
||||
|
||||
const newMethod = bitWriter(write => truncated.forEach(x => write(x, 24)));
|
||||
const newMethod = bitWriter(write => truncated.forEach(x => write(x, 24)));
|
||||
|
||||
console.log('old', oldMethod.byteLength);
|
||||
console.log('new', newMethod.byteLength);
|
||||
console.log('old', oldMethod.byteLength);
|
||||
console.log('new', newMethod.byteLength);
|
||||
}
|
||||
|
||||
export const results: any[] = [];
|
||||
|
||||
export function parseColorTest() {
|
||||
const iterations = 100000;
|
||||
const iterations = 100000;
|
||||
|
||||
function parseColorExperimental(value: string) {
|
||||
return (parseInt(value, 16) << 8) | 0xff;
|
||||
}
|
||||
function parseColorExperimental(value: string) {
|
||||
return (parseInt(value, 16) << 8) | 0xff;
|
||||
}
|
||||
|
||||
measure('COLOR parseColorWithAlpha', iterations, () => {
|
||||
return parseColorWithAlpha('ff4354', 1);
|
||||
});
|
||||
measure('COLOR parseColorWithAlpha', iterations, () => {
|
||||
return parseColorWithAlpha('ff4354', 1);
|
||||
});
|
||||
|
||||
measure('COLOR parseColorFast', iterations, () => {
|
||||
return parseColorFast('ff4354');
|
||||
});
|
||||
measure('COLOR parseColorFast', iterations, () => {
|
||||
return parseColorFast('ff4354');
|
||||
});
|
||||
|
||||
measure('COLOR parseColorExperimental', iterations, () => {
|
||||
return parseColorExperimental('ff4354');
|
||||
});
|
||||
measure('COLOR parseColorExperimental', iterations, () => {
|
||||
return parseColorExperimental('ff4354');
|
||||
});
|
||||
}
|
||||
|
||||
export function compareArrays() {
|
||||
const iterations = 100000;
|
||||
const a = [2423, 534534, 546124, 23412, 54364, 67756, 234234];
|
||||
const b = [564, 867867, 65645, 567567, 34534, 32453, 867867];
|
||||
const c = [2423, 534534, 546124, 23412, 54364, 67756, 234234];
|
||||
const d = [2423, 534534, 546124, 23412, 54364, 67756];
|
||||
let t: any;
|
||||
const iterations = 100000;
|
||||
const a = [2423, 534534, 546124, 23412, 54364, 67756, 234234];
|
||||
const b = [564, 867867, 65645, 567567, 34534, 32453, 867867];
|
||||
const c = [2423, 534534, 546124, 23412, 54364, 67756, 234234];
|
||||
const d = [2423, 534534, 546124, 23412, 54364, 67756];
|
||||
let t: any;
|
||||
|
||||
function compareArrays(a: number[], b: number[]) {
|
||||
if (a.length !== b.length)
|
||||
return false;
|
||||
function compareArrays(a: number[], b: number[]) {
|
||||
if (a.length !== b.length)
|
||||
return false;
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i])
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
measure('ARRAY _.isEqual', iterations, () => {
|
||||
t = isEqual(a, b);
|
||||
t = isEqual(a, c) || t;
|
||||
t = isEqual(a, d) || t;
|
||||
results.push(t);
|
||||
});
|
||||
measure('ARRAY _.isEqual', iterations, () => {
|
||||
t = isEqual(a, b);
|
||||
t = isEqual(a, c) || t;
|
||||
t = isEqual(a, d) || t;
|
||||
results.push(t);
|
||||
});
|
||||
|
||||
measure('ARRAY compareArrays', iterations, () => {
|
||||
t = compareArrays(a, b);
|
||||
t = compareArrays(a, c) || t;
|
||||
t = compareArrays(a, d) || t;
|
||||
results.push(t);
|
||||
});
|
||||
measure('ARRAY compareArrays', iterations, () => {
|
||||
t = compareArrays(a, b);
|
||||
t = compareArrays(a, c) || t;
|
||||
t = compareArrays(a, d) || t;
|
||||
results.push(t);
|
||||
});
|
||||
}
|
||||
|
||||
export function decode(data: string[]) {
|
||||
let manager = new PaletteManager();
|
||||
// manager = ({ addArray: (x: any) => x } as any);
|
||||
let manager = new PaletteManager();
|
||||
// manager = ({ addArray: (x: any) => x } as any);
|
||||
|
||||
measure('DECODE 1', 10000, i => {
|
||||
results.push(decodePonyInfo(data[i % data.length], manager));
|
||||
});
|
||||
measure('DECODE 1', 10000, i => {
|
||||
results.push(decodePonyInfo(data[i % data.length], manager));
|
||||
});
|
||||
|
||||
// console.log(((manager as any).palettes as any[]).map(x => x.length).join(', '));
|
||||
// console.log(((manager as any).palettes as any[]).map(x => x.length).join(', '));
|
||||
}
|
||||
|
||||
export function utfTest(messages: string[]) {
|
||||
const iterations = 300000;
|
||||
const iterations = 300000;
|
||||
|
||||
measure('old', iterations, i => {
|
||||
results.push(encodeString(messages[i % messages.length]));
|
||||
});
|
||||
measure('old', iterations, i => {
|
||||
results.push(encodeString(messages[i % messages.length]));
|
||||
});
|
||||
|
||||
measure('new', iterations, i => {
|
||||
results.push(encodeStringNew(messages[i % messages.length]));
|
||||
});
|
||||
measure('new', iterations, i => {
|
||||
results.push(encodeStringNew(messages[i % messages.length]));
|
||||
});
|
||||
|
||||
const encoder = new (window as any).TextEncoder('utf8');
|
||||
const encoder = new (window as any).TextEncoder('utf8');
|
||||
|
||||
measure('native', iterations, i => {
|
||||
results.push(encoder.encode(messages[i % messages.length]));
|
||||
});
|
||||
measure('native', iterations, i => {
|
||||
results.push(encoder.encode(messages[i % messages.length]));
|
||||
});
|
||||
}
|
||||
|
||||
export function arrayTest() {
|
||||
const iterations = 10000;
|
||||
const length = 100;
|
||||
const size = 24;
|
||||
const typed = new Int32Array(length * size);
|
||||
const typed2 = new Uint16Array(length * size);
|
||||
const iterations = 10000;
|
||||
const length = 100;
|
||||
const size = 24;
|
||||
const typed = new Int32Array(length * size);
|
||||
const typed2 = new Uint16Array(length * size);
|
||||
|
||||
for (let i = 0; i < typed.length; i++) {
|
||||
typed2[i] = typed[i] = Math.random() * 0xffff;
|
||||
}
|
||||
for (let i = 0; i < typed.length; i++) {
|
||||
typed2[i] = typed[i] = Math.random() * 0xffff;
|
||||
}
|
||||
|
||||
const objects = times(length, i => ({
|
||||
a: typed[i * size + 0],
|
||||
b: typed[i * size + 1],
|
||||
c: typed[i * size + 2],
|
||||
d: typed[i * size + 3],
|
||||
e: typed[i * size + 4],
|
||||
f: typed[i * size + 5],
|
||||
g: typed[i * size + 6],
|
||||
h: typed[i * size + 7],
|
||||
i: typed[i * size + 8],
|
||||
j: typed[i * size + 9],
|
||||
k: typed[i * size + 10],
|
||||
l: typed[i * size + 11],
|
||||
m: typed[i * size + 12],
|
||||
n: typed[i * size + 13],
|
||||
o: typed[i * size + 14],
|
||||
p: typed[i * size + 15],
|
||||
q: typed[i * size + 16],
|
||||
r: typed[i * size + 17],
|
||||
s: typed[i * size + 18],
|
||||
t: typed[i * size + 19],
|
||||
u: typed[i * size + 20],
|
||||
v: typed[i * size + 21],
|
||||
w: typed[i * size + 22],
|
||||
x: typed[i * size + 23],
|
||||
}));
|
||||
const objects = times(length, i => ({
|
||||
a: typed[i * size + 0],
|
||||
b: typed[i * size + 1],
|
||||
c: typed[i * size + 2],
|
||||
d: typed[i * size + 3],
|
||||
e: typed[i * size + 4],
|
||||
f: typed[i * size + 5],
|
||||
g: typed[i * size + 6],
|
||||
h: typed[i * size + 7],
|
||||
i: typed[i * size + 8],
|
||||
j: typed[i * size + 9],
|
||||
k: typed[i * size + 10],
|
||||
l: typed[i * size + 11],
|
||||
m: typed[i * size + 12],
|
||||
n: typed[i * size + 13],
|
||||
o: typed[i * size + 14],
|
||||
p: typed[i * size + 15],
|
||||
q: typed[i * size + 16],
|
||||
r: typed[i * size + 17],
|
||||
s: typed[i * size + 18],
|
||||
t: typed[i * size + 19],
|
||||
u: typed[i * size + 20],
|
||||
v: typed[i * size + 21],
|
||||
w: typed[i * size + 22],
|
||||
x: typed[i * size + 23],
|
||||
}));
|
||||
|
||||
const indexes = times(length, () => (Math.random() * length) | 0);
|
||||
const indexes = times(length, () => (Math.random() * length) | 0);
|
||||
|
||||
measure('typed', iterations, index => {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const offset = (indexes[(i + index) % length]) * 24;
|
||||
measure('typed', iterations, index => {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const offset = (indexes[(i + index) % length]) * 24;
|
||||
|
||||
for (let j = 0; j < size; j++) {
|
||||
sum += typed[offset + j];
|
||||
}
|
||||
}
|
||||
results.push(sum);
|
||||
});
|
||||
for (let j = 0; j < size; j++) {
|
||||
sum += typed[offset + j];
|
||||
}
|
||||
}
|
||||
results.push(sum);
|
||||
});
|
||||
|
||||
measure('typed2', iterations, index => {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const offset = (indexes[(i + index) % length]) * 24;
|
||||
measure('typed2', iterations, index => {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const offset = (indexes[(i + index) % length]) * 24;
|
||||
|
||||
for (let j = 0; j < size; j++) {
|
||||
sum += typed2[offset + j];
|
||||
}
|
||||
}
|
||||
results.push(sum);
|
||||
});
|
||||
for (let j = 0; j < size; j++) {
|
||||
sum += typed2[offset + j];
|
||||
}
|
||||
}
|
||||
results.push(sum);
|
||||
});
|
||||
|
||||
measure('objects', iterations, index => {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const offset = indexes[(i + index) % length];
|
||||
const o = objects[offset];
|
||||
sum += o.a + o.b + o.c + o.d + o.e + o.f + o.g + o.h + o.i + o.j + o.k + o.l +
|
||||
o.m + o.n + o.o + o.p + o.q + o.r + o.s + o.t + o.u + o.v + o.w + o.x;
|
||||
}
|
||||
results.push(sum);
|
||||
});
|
||||
measure('objects', iterations, index => {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const offset = indexes[(i + index) % length];
|
||||
const o = objects[offset];
|
||||
sum += o.a + o.b + o.c + o.d + o.e + o.f + o.g + o.h + o.i + o.j + o.k + o.l +
|
||||
o.m + o.n + o.o + o.p + o.q + o.r + o.s + o.t + o.u + o.v + o.w + o.x;
|
||||
}
|
||||
results.push(sum);
|
||||
});
|
||||
}
|
||||
|
||||
export function fillToOutlineTest() {
|
||||
const iterations = 100000;
|
||||
const iterations = 100000;
|
||||
|
||||
function fillToOutlineFast(color: string) {
|
||||
return colorToHexRGB(parseColorFast(color));
|
||||
}
|
||||
function fillToOutlineFast(color: string) {
|
||||
return colorToHexRGB(parseColorFast(color));
|
||||
}
|
||||
|
||||
measure('FILL-TO-OUTLINE fillToOutline', iterations, () => {
|
||||
fillToOutline('32cd32');
|
||||
});
|
||||
measure('FILL-TO-OUTLINE fillToOutline', iterations, () => {
|
||||
fillToOutline('32cd32');
|
||||
});
|
||||
|
||||
measure('FILL-TO-OUTLINE fillToOutlineFast', iterations, () => {
|
||||
fillToOutlineFast('32cd32');
|
||||
});
|
||||
measure('FILL-TO-OUTLINE fillToOutlineFast', iterations, () => {
|
||||
fillToOutlineFast('32cd32');
|
||||
});
|
||||
}
|
||||
|
||||
export function includeTest() {
|
||||
const iterations = 100000;
|
||||
const array = range(1000).map(() => random(0, 1000));
|
||||
let t = 0;
|
||||
const iterations = 100000;
|
||||
const array = range(1000).map(() => random(0, 1000));
|
||||
let t = 0;
|
||||
|
||||
// measure('INCLUDE _.includes', iterations, () => {
|
||||
// t += includes(array, array[random(0, 1000)]) as any | 0;
|
||||
// t += includes(array, array[random(0, 1000)]) as any | 0;
|
||||
// t += includes(array, array[random(0, 1000)]) as any | 0;
|
||||
// });
|
||||
// measure('INCLUDE _.includes', iterations, () => {
|
||||
// t += includes(array, array[random(0, 1000)]) as any | 0;
|
||||
// t += includes(array, array[random(0, 1000)]) as any | 0;
|
||||
// t += includes(array, array[random(0, 1000)]) as any | 0;
|
||||
// });
|
||||
|
||||
measure('INCLUDE includes', iterations, () => {
|
||||
t += utilsIncludes(array, array[random(0, 1000)]) as any | 0;
|
||||
t += utilsIncludes(array, array[random(0, 1000)]) as any | 0;
|
||||
t += utilsIncludes(array, array[random(0, 1000)]) as any | 0;
|
||||
});
|
||||
measure('INCLUDE includes', iterations, () => {
|
||||
t += utilsIncludes(array, array[random(0, 1000)]) as any | 0;
|
||||
t += utilsIncludes(array, array[random(0, 1000)]) as any | 0;
|
||||
t += utilsIncludes(array, array[random(0, 1000)]) as any | 0;
|
||||
});
|
||||
|
||||
measure('INCLUDE indexOf !== -1', iterations, () => {
|
||||
t += (array.indexOf(array[random(0, 1000)]) !== -1) as any | 0;
|
||||
t += (array.indexOf(array[random(0, 1000)]) !== -1) as any | 0;
|
||||
t += (array.indexOf(array[random(0, 1000)]) !== -1) as any | 0;
|
||||
});
|
||||
measure('INCLUDE indexOf !== -1', iterations, () => {
|
||||
t += (array.indexOf(array[random(0, 1000)]) !== -1) as any | 0;
|
||||
t += (array.indexOf(array[random(0, 1000)]) !== -1) as any | 0;
|
||||
t += (array.indexOf(array[random(0, 1000)]) !== -1) as any | 0;
|
||||
});
|
||||
|
||||
results.push(t);
|
||||
results.push(t);
|
||||
}
|
||||
|
||||
export function toColorListTest() {
|
||||
function toColorList2Old(colors: number[]) {
|
||||
return [0, ...colors.map(c => c || 0xff)];
|
||||
}
|
||||
function toColorList2Old(colors: number[]) {
|
||||
return [0, ...colors.map(c => c || 0xff)];
|
||||
}
|
||||
|
||||
const iterations = 100000;
|
||||
let t: any[] = [];
|
||||
const iterations = 100000;
|
||||
let t: any[] = [];
|
||||
|
||||
measure('TOCOLORLIST2 old', iterations, () => {
|
||||
t.push(toColorList2Old([1, 2, Date.now(), Date.now(), 5, 6]));
|
||||
});
|
||||
measure('TOCOLORLIST2 old', iterations, () => {
|
||||
t.push(toColorList2Old([1, 2, Date.now(), Date.now(), 5, 6]));
|
||||
});
|
||||
|
||||
measure('TOCOLORLIST2 new', iterations, () => {
|
||||
t.push(toColorListNumber([1, 2, Date.now(), Date.now(), 5, 6]));
|
||||
});
|
||||
measure('TOCOLORLIST2 new', iterations, () => {
|
||||
t.push(toColorListNumber([1, 2, Date.now(), Date.now(), 5, 6]));
|
||||
});
|
||||
|
||||
results.push(t);
|
||||
results.push(t);
|
||||
}
|
||||
|
||||
export function copyTest() {
|
||||
const iterations = 10000;
|
||||
let t: any[] = [];
|
||||
const src = new Uint32Array(1000);
|
||||
const dst = new Uint32Array(10000);
|
||||
const iterations = 10000;
|
||||
let t: any[] = [];
|
||||
const src = new Uint32Array(1000);
|
||||
const dst = new Uint32Array(10000);
|
||||
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
src[i] = Math.random() * 10000;
|
||||
}
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
src[i] = Math.random() * 10000;
|
||||
}
|
||||
|
||||
for (let i = 0; i < dst.length; i++) {
|
||||
dst[i] = Math.random() * 10000;
|
||||
}
|
||||
for (let i = 0; i < dst.length; i++) {
|
||||
dst[i] = Math.random() * 10000;
|
||||
}
|
||||
|
||||
measure('ONE_BY_ONE', iterations, iteration => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
for (let j = 0; j < src.length; j++) {
|
||||
dst[1000 * i + j] = src[j];
|
||||
}
|
||||
}
|
||||
measure('ONE_BY_ONE', iterations, iteration => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
for (let j = 0; j < src.length; j++) {
|
||||
dst[1000 * i + j] = src[j];
|
||||
}
|
||||
}
|
||||
|
||||
t.push(dst, iteration);
|
||||
});
|
||||
t.push(dst, iteration);
|
||||
});
|
||||
|
||||
measure('COPY_BUFFER', iterations, iteration => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
dst.set(src, 1000 * i);
|
||||
}
|
||||
measure('COPY_BUFFER', iterations, iteration => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
dst.set(src, 1000 * i);
|
||||
}
|
||||
|
||||
t.push(dst, iteration);
|
||||
});
|
||||
t.push(dst, iteration);
|
||||
});
|
||||
|
||||
results.push(t);
|
||||
results.push(t);
|
||||
}
|
||||
|
||||
export function regexTest(testStrings: string[]) {
|
||||
const iterations = 1000000;
|
||||
const t: any[] = [];
|
||||
const iterations = 1000000;
|
||||
const t: any[] = [];
|
||||
|
||||
measure('WITH_GROUPS', iterations, iteration => {
|
||||
const test = testStrings[iteration % testStrings.length];
|
||||
t.push(test.replace(/(a|b)(.)(.)(.)(.)(.)/, 'X'));
|
||||
});
|
||||
measure('WITH_GROUPS', iterations, iteration => {
|
||||
const test = testStrings[iteration % testStrings.length];
|
||||
t.push(test.replace(/(a|b)(.)(.)(.)(.)(.)/, 'X'));
|
||||
});
|
||||
|
||||
measure('WITHOUT_GROUPS', iterations, iteration => {
|
||||
const test = testStrings[iteration % testStrings.length];
|
||||
t.push(test.replace(/(?:a|b)(?:.)(?:.)(?:.)(?:.)(?:.)/, 'X'));
|
||||
});
|
||||
measure('WITHOUT_GROUPS', iterations, iteration => {
|
||||
const test = testStrings[iteration % testStrings.length];
|
||||
t.push(test.replace(/(?:a|b)(?:.)(?:.)(?:.)(?:.)(?:.)/, 'X'));
|
||||
});
|
||||
|
||||
results.push(t);
|
||||
results.push(t);
|
||||
}
|
||||
|
||||
export function swearTest(testStrings: string[]) {
|
||||
const iterations = 10000;
|
||||
const t: any[] = [];
|
||||
const iterations = 10000;
|
||||
const t: any[] = [];
|
||||
|
||||
measure('TEST', iterations, iteration => {
|
||||
const test = testStrings[iteration % testStrings.length];
|
||||
t.push(filterBadWords(test));
|
||||
});
|
||||
measure('TEST', iterations, iteration => {
|
||||
const test = testStrings[iteration % testStrings.length];
|
||||
t.push(filterBadWords(test));
|
||||
});
|
||||
|
||||
results.push(t);
|
||||
results.push(t);
|
||||
}
|
||||
|
||||
export function swearEntryTest(testStrings: string[], onResult: (output: string) => void) {
|
||||
const iterations = 2000;
|
||||
const output: any[] = [];
|
||||
const entries = createMatchEntries();
|
||||
const iterations = 2000;
|
||||
const output: any[] = [];
|
||||
const entries = createMatchEntries();
|
||||
|
||||
for (const e of entries) {
|
||||
const start = performance.now();
|
||||
for (const e of entries) {
|
||||
const start = performance.now();
|
||||
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const test = testStrings[i % testStrings.length];
|
||||
results.push(test.replace(e.regex, '*****'));
|
||||
}
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const test = testStrings[i % testStrings.length];
|
||||
results.push(test.replace(e.regex, '*****'));
|
||||
}
|
||||
|
||||
const diff = performance.now() - start;
|
||||
output.push({ e, diff });
|
||||
}
|
||||
const diff = performance.now() - start;
|
||||
output.push({ e, diff });
|
||||
}
|
||||
|
||||
onResult(output
|
||||
.sort((a, b) => b.diff - a.diff)
|
||||
.map(x => `${x.diff.toFixed(2).padStart(6)} "${x.e.line}"`)
|
||||
.join('\n'));
|
||||
onResult(output
|
||||
.sort((a, b) => b.diff - a.diff)
|
||||
.map(x => `${x.diff.toFixed(2).padStart(6)} "${x.e.line}"`)
|
||||
.join('\n'));
|
||||
}
|
||||
|
||||
(window as any).__results = results;
|
||||
|
||||
@@ -9,164 +9,164 @@ import { Rect, Point } from '../../../common/interfaces';
|
||||
import { toWorldX, toWorldY } from '../../../common/positionUtils';
|
||||
|
||||
export function getRegionsBounds(client: any, region: any) {
|
||||
const screenSize = client.screenSize;
|
||||
const width = Math.ceil(((1.3 * screenSize.width) / region.size) / 2) * 2 + 2;
|
||||
const height = Math.ceil(((1.3 * screenSize.height) / region.size) / 2) * 2 + 2;
|
||||
return rect(region.x - Math.ceil(width / 2), region.y - Math.ceil(height / 2), width, height);
|
||||
const screenSize = client.screenSize;
|
||||
const width = Math.ceil(((1.3 * screenSize.width) / region.size) / 2) * 2 + 2;
|
||||
const height = Math.ceil(((1.3 * screenSize.height) / region.size) / 2) * 2 + 2;
|
||||
return rect(region.x - Math.ceil(width / 2), region.y - Math.ceil(height / 2), width, height);
|
||||
}
|
||||
|
||||
export function getRegionsBoundsCameraBased(_entity: Point, camera: Rect, regionSize: number) {
|
||||
const left = Math.floor(camera.x / regionSize - 0.5);
|
||||
const top = Math.floor(camera.y / regionSize - 0.5);
|
||||
const right = Math.floor((camera.x + camera.w) / regionSize + 0.5);
|
||||
const bottom = Math.floor((camera.y + camera.h) / regionSize + 0.5);
|
||||
return rect(left, top, right - left, bottom - top);
|
||||
const left = Math.floor(camera.x / regionSize - 0.5);
|
||||
const top = Math.floor(camera.y / regionSize - 0.5);
|
||||
const right = Math.floor((camera.x + camera.w) / regionSize + 0.5);
|
||||
const bottom = Math.floor((camera.y + camera.h) / regionSize + 0.5);
|
||||
return rect(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tools-regions',
|
||||
templateUrl: 'tools-regions.pug',
|
||||
selector: 'tools-regions',
|
||||
templateUrl: 'tools-regions.pug',
|
||||
})
|
||||
export class ToolsRegions implements OnInit, OnDestroy {
|
||||
currentMapSize = 80;
|
||||
tileWidth = tileWidth;
|
||||
tileHeight = tileHeight;
|
||||
screen = { width: 390, height: 580 };
|
||||
// screen = { width: 1920, height: 1080 };
|
||||
regionsX = 18;
|
||||
regionsY = 16;
|
||||
regionSize = 8;
|
||||
scale = 0.25;
|
||||
zoom = 2;
|
||||
regions: string[][];
|
||||
camera = createCamera();
|
||||
approxCamera = createCamera();
|
||||
player = { x: 0, y: 0 };
|
||||
frame = 0;
|
||||
lastFrame = 0;
|
||||
constructor() {
|
||||
this.regions = times(this.regionsY, () => times(this.regionsX, () => ''));
|
||||
}
|
||||
ngOnInit() {
|
||||
this.update();
|
||||
this.frame = requestAnimationFrame(this.tick);
|
||||
}
|
||||
ngOnDestroy() {
|
||||
cancelAnimationFrame(this.frame);
|
||||
}
|
||||
update() {
|
||||
const regionWidth = this.regionSize * tileWidth;
|
||||
const regionHeight = this.regionSize * tileHeight;
|
||||
const map = { width: this.regionsX * this.regionSize, height: this.regionsY * this.regionSize } as any;
|
||||
currentMapSize = 80;
|
||||
tileWidth = tileWidth;
|
||||
tileHeight = tileHeight;
|
||||
screen = { width: 390, height: 580 };
|
||||
// screen = { width: 1920, height: 1080 };
|
||||
regionsX = 18;
|
||||
regionsY = 16;
|
||||
regionSize = 8;
|
||||
scale = 0.25;
|
||||
zoom = 2;
|
||||
regions: string[][];
|
||||
camera = createCamera();
|
||||
approxCamera = createCamera();
|
||||
player = { x: 0, y: 0 };
|
||||
frame = 0;
|
||||
lastFrame = 0;
|
||||
constructor() {
|
||||
this.regions = times(this.regionsY, () => times(this.regionsX, () => ''));
|
||||
}
|
||||
ngOnInit() {
|
||||
this.update();
|
||||
this.frame = requestAnimationFrame(this.tick);
|
||||
}
|
||||
ngOnDestroy() {
|
||||
cancelAnimationFrame(this.frame);
|
||||
}
|
||||
update() {
|
||||
const regionWidth = this.regionSize * tileWidth;
|
||||
const regionHeight = this.regionSize * tileHeight;
|
||||
const map = { width: this.regionsX * this.regionSize, height: this.regionsY * this.regionSize } as any;
|
||||
|
||||
this.camera.w = Math.ceil(this.screen.width / this.zoom);
|
||||
this.camera.h = Math.ceil(this.screen.height / this.zoom);
|
||||
updateCamera(this.camera, this.player, map);
|
||||
this.camera.w = Math.ceil(this.screen.width / this.zoom);
|
||||
this.camera.h = Math.ceil(this.screen.height / this.zoom);
|
||||
updateCamera(this.camera, this.player, map);
|
||||
|
||||
this.approxCamera.w = this.camera.w * 1.3;
|
||||
this.approxCamera.h = this.camera.h * 1.3;
|
||||
centerCameraOn(this.approxCamera, this.player);
|
||||
updateCamera(this.approxCamera, this.player, map);
|
||||
this.approxCamera.w = this.camera.w * 1.3;
|
||||
this.approxCamera.h = this.camera.h * 1.3;
|
||||
centerCameraOn(this.approxCamera, this.player);
|
||||
updateCamera(this.approxCamera, this.player, map);
|
||||
|
||||
this.regions.forEach(x => fill(x, ''));
|
||||
this.regions.forEach(x => fill(x, ''));
|
||||
|
||||
const rx = clamp(Math.floor(this.player.x / this.regionSize), 0, this.regionsX - 1);
|
||||
const ry = clamp(Math.floor(this.player.y / this.regionSize), 0, this.regionsY - 1);
|
||||
const rx = clamp(Math.floor(this.player.x / this.regionSize), 0, this.regionsX - 1);
|
||||
const ry = clamp(Math.floor(this.player.y / this.regionSize), 0, this.regionsY - 1);
|
||||
|
||||
const bounds1 = getRegionsBounds(
|
||||
{
|
||||
screenSize: {
|
||||
width: Math.ceil(this.camera.w / tileWidth),
|
||||
height: Math.ceil(this.camera.h / tileHeight)
|
||||
}
|
||||
},
|
||||
{ size: this.regionSize, x: rx, y: ry });
|
||||
const bounds1 = getRegionsBounds(
|
||||
{
|
||||
screenSize: {
|
||||
width: Math.ceil(this.camera.w / tileWidth),
|
||||
height: Math.ceil(this.camera.h / tileHeight)
|
||||
}
|
||||
},
|
||||
{ size: this.regionSize, x: rx, y: ry });
|
||||
|
||||
const bounds2 = getRegionsBoundsCameraBased(
|
||||
this.player,
|
||||
rect(toWorldX(this.camera.x), toWorldY(this.camera.y), toWorldX(this.camera.w), toWorldY(this.camera.h)),
|
||||
this.regionSize);
|
||||
const bounds2 = getRegionsBoundsCameraBased(
|
||||
this.player,
|
||||
rect(toWorldX(this.camera.x), toWorldY(this.camera.y), toWorldX(this.camera.w), toWorldY(this.camera.h)),
|
||||
this.regionSize);
|
||||
|
||||
const bounds = [bounds1, bounds2][1];
|
||||
const bounds = [bounds1, bounds2][1];
|
||||
|
||||
for (let ix = 0; ix <= bounds.w; ix++) {
|
||||
for (let iy = 0; iy <= bounds.h; iy++) {
|
||||
const yy = bounds.y + iy;
|
||||
const xx = bounds.x + ix;
|
||||
for (let ix = 0; ix <= bounds.w; ix++) {
|
||||
for (let iy = 0; iy <= bounds.h; iy++) {
|
||||
const yy = bounds.y + iy;
|
||||
const xx = bounds.x + ix;
|
||||
|
||||
if (xx >= 0 && xx < this.regionsX && yy >= 0 && yy < this.regionsY) {
|
||||
this.regions[yy][xx] = 'Sienna';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xx >= 0 && xx < this.regionsX && yy >= 0 && yy < this.regionsY) {
|
||||
this.regions[yy][xx] = 'Sienna';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let x = 0; x < this.regionsX; x++) {
|
||||
for (let y = 0; y < this.regionsY; y++) {
|
||||
if (isAreaVisible(this.camera, x * regionWidth, y * regionHeight, regionWidth, regionHeight)) {
|
||||
if (this.regions[y][x] === 'Sienna') {
|
||||
this.regions[y][x] = 'SeaGreen';
|
||||
} else {
|
||||
this.regions[y][x] = 'Crimson';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let x = 0; x < this.regionsX; x++) {
|
||||
for (let y = 0; y < this.regionsY; y++) {
|
||||
if (isAreaVisible(this.camera, x * regionWidth, y * regionHeight, regionWidth, regionHeight)) {
|
||||
if (this.regions[y][x] === 'Sienna') {
|
||||
this.regions[y][x] = 'SeaGreen';
|
||||
} else {
|
||||
this.regions[y][x] = 'Crimson';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.regions[ry][rx] = 'MediumSeaGreen';
|
||||
}
|
||||
dragRegion({ x, y }: AgDragEvent) {
|
||||
this.player.x = x / (this.tileWidth * this.scale);
|
||||
this.player.y = y / (this.tileHeight * this.scale);
|
||||
this.update();
|
||||
}
|
||||
private right = false;
|
||||
private left = false;
|
||||
private up = false;
|
||||
private down = false;
|
||||
@HostListener('window:keydown', ['$event'])
|
||||
keydown(e: KeyboardEvent) {
|
||||
if (e.keyCode === Key.KEY_P) {
|
||||
this.zoom = this.zoom === 4 ? 1 : (this.zoom + 1);
|
||||
this.update();
|
||||
} else if (e.keyCode === Key.RIGHT) {
|
||||
this.right = true;
|
||||
} else if (e.keyCode === Key.LEFT) {
|
||||
this.left = true;
|
||||
} else if (e.keyCode === Key.UP) {
|
||||
this.up = true;
|
||||
} else if (e.keyCode === Key.DOWN) {
|
||||
this.down = true;
|
||||
}
|
||||
}
|
||||
@HostListener('window:keyup', ['$event'])
|
||||
keyup(e: KeyboardEvent) {
|
||||
if (e.keyCode === Key.RIGHT) {
|
||||
this.right = false;
|
||||
} else if (e.keyCode === Key.LEFT) {
|
||||
this.left = false;
|
||||
} else if (e.keyCode === Key.UP) {
|
||||
this.up = false;
|
||||
} else if (e.keyCode === Key.DOWN) {
|
||||
this.down = false;
|
||||
}
|
||||
}
|
||||
tick = (now: number) => {
|
||||
this.frame = requestAnimationFrame(this.tick);
|
||||
const delta = (now - this.lastFrame) / 1000;
|
||||
this.lastFrame = now;
|
||||
this.regions[ry][rx] = 'MediumSeaGreen';
|
||||
}
|
||||
dragRegion({ x, y }: AgDragEvent) {
|
||||
this.player.x = x / (this.tileWidth * this.scale);
|
||||
this.player.y = y / (this.tileHeight * this.scale);
|
||||
this.update();
|
||||
}
|
||||
private right = false;
|
||||
private left = false;
|
||||
private up = false;
|
||||
private down = false;
|
||||
@HostListener('window:keydown', ['$event'])
|
||||
keydown(e: KeyboardEvent) {
|
||||
if (e.keyCode === Key.KEY_P) {
|
||||
this.zoom = this.zoom === 4 ? 1 : (this.zoom + 1);
|
||||
this.update();
|
||||
} else if (e.keyCode === Key.RIGHT) {
|
||||
this.right = true;
|
||||
} else if (e.keyCode === Key.LEFT) {
|
||||
this.left = true;
|
||||
} else if (e.keyCode === Key.UP) {
|
||||
this.up = true;
|
||||
} else if (e.keyCode === Key.DOWN) {
|
||||
this.down = true;
|
||||
}
|
||||
}
|
||||
@HostListener('window:keyup', ['$event'])
|
||||
keyup(e: KeyboardEvent) {
|
||||
if (e.keyCode === Key.RIGHT) {
|
||||
this.right = false;
|
||||
} else if (e.keyCode === Key.LEFT) {
|
||||
this.left = false;
|
||||
} else if (e.keyCode === Key.UP) {
|
||||
this.up = false;
|
||||
} else if (e.keyCode === Key.DOWN) {
|
||||
this.down = false;
|
||||
}
|
||||
}
|
||||
tick = (now: number) => {
|
||||
this.frame = requestAnimationFrame(this.tick);
|
||||
const delta = (now - this.lastFrame) / 1000;
|
||||
this.lastFrame = now;
|
||||
|
||||
let dx = 0;
|
||||
let dy = 0;
|
||||
let dx = 0;
|
||||
let dy = 0;
|
||||
|
||||
if (this.right) dx += 1;
|
||||
if (this.left) dx -= 1;
|
||||
if (this.up) dy -= 1;
|
||||
if (this.down) dy += 1;
|
||||
if (this.right) dx += 1;
|
||||
if (this.left) dx -= 1;
|
||||
if (this.up) dy -= 1;
|
||||
if (this.down) dy += 1;
|
||||
|
||||
if (dx || dy) {
|
||||
this.player.x += dx * delta * PONY_SPEED_TROT;
|
||||
this.player.y += dy * delta * PONY_SPEED_TROT;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
if (dx || dy) {
|
||||
this.player.x += dx * delta * PONY_SPEED_TROT;
|
||||
this.player.y += dy * delta * PONY_SPEED_TROT;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,68 +9,68 @@ import { at } from '../../../common/utils';
|
||||
import { sheets, Sheet } from '../../../common/sheets';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-sheet',
|
||||
templateUrl: 'tools-sheet.pug',
|
||||
styleUrls: ['tools-sheet.scss'],
|
||||
selector: 'tools-sheet',
|
||||
templateUrl: 'tools-sheet.pug',
|
||||
styleUrls: ['tools-sheet.scss'],
|
||||
})
|
||||
export class ToolsSheet implements OnInit {
|
||||
readonly homeIcon = faHome;
|
||||
readonly syncIcon = faSync;
|
||||
readonly imageIcon = faFileImage;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
sheets = sheets;
|
||||
sheet = sheets[0] as Sheet;
|
||||
scale = 2;
|
||||
rows = 1;
|
||||
cols = 1;
|
||||
pattern = -1;
|
||||
constructor(private storage: StorageService) {
|
||||
const sheet = at(this.sheets, storage.getInt('tools-sheet-sheet'))!;
|
||||
readonly homeIcon = faHome;
|
||||
readonly syncIcon = faSync;
|
||||
readonly imageIcon = faFileImage;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
sheets = sheets;
|
||||
sheet = sheets[0] as Sheet;
|
||||
scale = 2;
|
||||
rows = 1;
|
||||
cols = 1;
|
||||
pattern = -1;
|
||||
constructor(private storage: StorageService) {
|
||||
const sheet = at(this.sheets, storage.getInt('tools-sheet-sheet'))!;
|
||||
|
||||
if ('name' in sheet) {
|
||||
this.setSheet(sheet);
|
||||
}
|
||||
}
|
||||
ngOnInit() {
|
||||
loadAndInitSpriteSheets()
|
||||
.then(() => this.redraw());
|
||||
}
|
||||
setSheet(sheet: Sheet) {
|
||||
sheet = sheet.spacer ? this.sheets[0] as Sheet : sheet;
|
||||
this.sheet = sheet;
|
||||
this.cols = getCols(sheet);
|
||||
this.rows = getRows(sheet);
|
||||
this.redraw();
|
||||
this.storage.setInt('tools-sheet-sheet', this.sheets.indexOf(sheet));
|
||||
}
|
||||
png() {
|
||||
this.redraw();
|
||||
saveCanvas(this.canvas.nativeElement, 'sheet.png');
|
||||
}
|
||||
psd() {
|
||||
const psd = createPsd(this.sheet, this.rows, this.cols);
|
||||
psd.canvas = drawPsd(psd, 1);
|
||||
savePsd(psd, `${this.sheet.file}.psd`);
|
||||
}
|
||||
allPSDs() {
|
||||
this.sheets
|
||||
.filter(x => 'name' in x && !!x.file)
|
||||
.map(x => x as Sheet)
|
||||
.forEach(sheet => {
|
||||
const rows = getRows(sheet);
|
||||
const cols = getCols(sheet);
|
||||
const psd = createPsd(sheet, rows, cols);
|
||||
psd.canvas = drawPsd(psd, 1);
|
||||
savePsd(psd, `${sheet.file}.psd`);
|
||||
});
|
||||
}
|
||||
redraw() {
|
||||
if (this.canvas) {
|
||||
const psd = createPsd(this.sheet, this.rows, this.cols);
|
||||
const layers = compact(psd.children!.map(c => c.children));
|
||||
const patterns = compact(layers.map(xs => xs.find(x => x.name === `pattern ${this.pattern}`)));
|
||||
patterns.forEach(x => x.hidden = false);
|
||||
drawPsd(psd, this.scale, this.canvas.nativeElement);
|
||||
}
|
||||
}
|
||||
if ('name' in sheet) {
|
||||
this.setSheet(sheet);
|
||||
}
|
||||
}
|
||||
ngOnInit() {
|
||||
loadAndInitSpriteSheets()
|
||||
.then(() => this.redraw());
|
||||
}
|
||||
setSheet(sheet: Sheet) {
|
||||
sheet = sheet.spacer ? this.sheets[0] as Sheet : sheet;
|
||||
this.sheet = sheet;
|
||||
this.cols = getCols(sheet);
|
||||
this.rows = getRows(sheet);
|
||||
this.redraw();
|
||||
this.storage.setInt('tools-sheet-sheet', this.sheets.indexOf(sheet));
|
||||
}
|
||||
png() {
|
||||
this.redraw();
|
||||
saveCanvas(this.canvas.nativeElement, 'sheet.png');
|
||||
}
|
||||
psd() {
|
||||
const psd = createPsd(this.sheet, this.rows, this.cols);
|
||||
psd.canvas = drawPsd(psd, 1);
|
||||
savePsd(psd, `${this.sheet.file}.psd`);
|
||||
}
|
||||
allPSDs() {
|
||||
this.sheets
|
||||
.filter(x => 'name' in x && !!x.file)
|
||||
.map(x => x as Sheet)
|
||||
.forEach(sheet => {
|
||||
const rows = getRows(sheet);
|
||||
const cols = getCols(sheet);
|
||||
const psd = createPsd(sheet, rows, cols);
|
||||
psd.canvas = drawPsd(psd, 1);
|
||||
savePsd(psd, `${sheet.file}.psd`);
|
||||
});
|
||||
}
|
||||
redraw() {
|
||||
if (this.canvas) {
|
||||
const psd = createPsd(this.sheet, this.rows, this.cols);
|
||||
const layers = compact(psd.children!.map(c => c.children));
|
||||
const patterns = compact(layers.map(xs => xs.find(x => x.name === `pattern ${this.pattern}`)));
|
||||
patterns.forEach(x => x.hidden = false);
|
||||
drawPsd(psd, this.scale, this.canvas.nativeElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,133 +7,133 @@ import { AnimatorState } from '../../../common/animator';
|
||||
import { distance, flatten } from '../../../common/utils';
|
||||
|
||||
function getPos(key: string, type: 'x' | 'y', defaultValue = 100) {
|
||||
const item = localStorage.getItem(`tools-stats-${key}-${type}`);
|
||||
return item ? parseInt(item, 10) : defaultValue;
|
||||
const item = localStorage.getItem(`tools-stats-${key}-${type}`);
|
||||
return item ? parseInt(item, 10) : defaultValue;
|
||||
}
|
||||
|
||||
function setPos(key: string, type: 'x' | 'y', value: number) {
|
||||
localStorage.setItem(`tools-stats-${key}-${type}`, value.toString());
|
||||
localStorage.setItem(`tools-stats-${key}-${type}`, value.toString());
|
||||
}
|
||||
|
||||
const defaultPositions: any = {
|
||||
'any': { 'x': 917, 'y': 43 },
|
||||
'standing': { 'x': 317, 'y': 300 },
|
||||
'trotting': { 'x': 660, 'y': 304 },
|
||||
'swimming': { 'x': 988, 'y': 435 },
|
||||
'swimming-to-trotting': { 'x': 747, 'y': 548 },
|
||||
'trotting-to-swimming': { 'x': 805, 'y': 413 },
|
||||
'booping': { 'x': 106, 'y': 301 },
|
||||
'booping-sitting': { 'x': 111, 'y': 569 },
|
||||
'booping-lying': { 'x': 127, 'y': 821 },
|
||||
'booping-flying': { 'x': 110, 'y': 64 },
|
||||
'sitting': { 'x': 312, 'y': 569 },
|
||||
'sitting-down': { 'x': 186, 'y': 437 },
|
||||
'standing-up': { 'x': 313, 'y': 436 },
|
||||
'sitting-to-trotting': { 'x': 517, 'y': 500 },
|
||||
'lying': { 'x': 326, 'y': 818 },
|
||||
'lying-down': { 'x': 254, 'y': 692 },
|
||||
'sitting-up': { 'x': 385, 'y': 682 },
|
||||
'lying-to-trotting': { 'x': 541, 'y': 731 },
|
||||
'hovering': { 'x': 334, 'y': 21 },
|
||||
'flying': { 'x': 641, 'y': 29 },
|
||||
'flying-up': { 'x': 378, 'y': 182 },
|
||||
'flying-down': { 'x': 247, 'y': 177 },
|
||||
'trotting-to-flying': { 'x': 601, 'y': 188 },
|
||||
'flying-to-trotting': { 'x': 805, 'y': 270 },
|
||||
'swinging': { 'x': 484, 'y': 238 },
|
||||
'swimming-to-flying': { 'x': 1063, 'y': 182 },
|
||||
'flying-to-swimming': { 'x': 938, 'y': 232 },
|
||||
'booping-swimming': { 'x': 1144, 'y': 432 }
|
||||
'any': { 'x': 917, 'y': 43 },
|
||||
'standing': { 'x': 317, 'y': 300 },
|
||||
'trotting': { 'x': 660, 'y': 304 },
|
||||
'swimming': { 'x': 988, 'y': 435 },
|
||||
'swimming-to-trotting': { 'x': 747, 'y': 548 },
|
||||
'trotting-to-swimming': { 'x': 805, 'y': 413 },
|
||||
'booping': { 'x': 106, 'y': 301 },
|
||||
'booping-sitting': { 'x': 111, 'y': 569 },
|
||||
'booping-lying': { 'x': 127, 'y': 821 },
|
||||
'booping-flying': { 'x': 110, 'y': 64 },
|
||||
'sitting': { 'x': 312, 'y': 569 },
|
||||
'sitting-down': { 'x': 186, 'y': 437 },
|
||||
'standing-up': { 'x': 313, 'y': 436 },
|
||||
'sitting-to-trotting': { 'x': 517, 'y': 500 },
|
||||
'lying': { 'x': 326, 'y': 818 },
|
||||
'lying-down': { 'x': 254, 'y': 692 },
|
||||
'sitting-up': { 'x': 385, 'y': 682 },
|
||||
'lying-to-trotting': { 'x': 541, 'y': 731 },
|
||||
'hovering': { 'x': 334, 'y': 21 },
|
||||
'flying': { 'x': 641, 'y': 29 },
|
||||
'flying-up': { 'x': 378, 'y': 182 },
|
||||
'flying-down': { 'x': 247, 'y': 177 },
|
||||
'trotting-to-flying': { 'x': 601, 'y': 188 },
|
||||
'flying-to-trotting': { 'x': 805, 'y': 270 },
|
||||
'swinging': { 'x': 484, 'y': 238 },
|
||||
'swimming-to-flying': { 'x': 1063, 'y': 182 },
|
||||
'flying-to-swimming': { 'x': 938, 'y': 232 },
|
||||
'booping-swimming': { 'x': 1144, 'y': 432 }
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'tools-states',
|
||||
templateUrl: 'tools-states.pug',
|
||||
styleUrls: ['tools-states.scss'],
|
||||
selector: 'tools-states',
|
||||
templateUrl: 'tools-states.pug',
|
||||
styleUrls: ['tools-states.scss'],
|
||||
})
|
||||
export class ToolsStates {
|
||||
readonly homeIcon = faHome;
|
||||
private startX = 0;
|
||||
private startY = 0;
|
||||
arrowColors = ['orange', 'red', 'lime'];
|
||||
states = ponyStates.map(state => {
|
||||
const def = defaultPositions[state.name] || { x: 0, y: 0 };
|
||||
readonly homeIcon = faHome;
|
||||
private startX = 0;
|
||||
private startY = 0;
|
||||
arrowColors = ['orange', 'red', 'lime'];
|
||||
states = ponyStates.map(state => {
|
||||
const def = defaultPositions[state.name] || { x: 0, y: 0 };
|
||||
|
||||
return {
|
||||
color: state.name === 'any' ? 'orange' : (state.animation.loop ? 'LightSeaGreen' : 'cornflowerblue'),
|
||||
name: state.name,
|
||||
variants: Object.keys(state.variants || {}).join(', '),
|
||||
state,
|
||||
x: getPos(state.name, 'x', def.x),
|
||||
y: getPos(state.name, 'y', def.y),
|
||||
};
|
||||
});
|
||||
arrows: { path: string; color: string; }[] = [];
|
||||
times: { x: number; y: number; color: string; text: string; title?: string; }[] = [];
|
||||
constructor() {
|
||||
this.updateArrows();
|
||||
}
|
||||
drag(state: any, { dx, dy, type }: AgDragEvent) {
|
||||
if (type === 'start') {
|
||||
this.startX = state.x;
|
||||
this.startY = state.y;
|
||||
}
|
||||
return {
|
||||
color: state.name === 'any' ? 'orange' : (state.animation.loop ? 'LightSeaGreen' : 'cornflowerblue'),
|
||||
name: state.name,
|
||||
variants: Object.keys(state.variants || {}).join(', '),
|
||||
state,
|
||||
x: getPos(state.name, 'x', def.x),
|
||||
y: getPos(state.name, 'y', def.y),
|
||||
};
|
||||
});
|
||||
arrows: { path: string; color: string; }[] = [];
|
||||
times: { x: number; y: number; color: string; text: string; title?: string; }[] = [];
|
||||
constructor() {
|
||||
this.updateArrows();
|
||||
}
|
||||
drag(state: any, { dx, dy, type }: AgDragEvent) {
|
||||
if (type === 'start') {
|
||||
this.startX = state.x;
|
||||
this.startY = state.y;
|
||||
}
|
||||
|
||||
setPos(state.name, 'x', state.x = this.startX + dx);
|
||||
setPos(state.name, 'y', state.y = this.startY + dy);
|
||||
this.updateArrows();
|
||||
}
|
||||
logPositions() {
|
||||
const positions = fromPairs(this.states.map(({ name, x, y }) => [name, { x, y }]));
|
||||
console.log(JSON.stringify(positions).replace(/"/g, `'`).replace(/},/g, '},\n'));
|
||||
}
|
||||
private updateArrows() {
|
||||
this.times = [];
|
||||
this.arrows = flatten(this.states.map(s => s.state.from.map(f => ({
|
||||
to: s,
|
||||
from: this.findState(f.state),
|
||||
color: f.exitAfter === 0 ? (f.keepTime ? 'orange' : 'red') : 'lime',
|
||||
exitAfter: f.exitAfter,
|
||||
enterTime: f.enterTime,
|
||||
onlyDirectTo: f.onlyDirectTo,
|
||||
}))))
|
||||
.filter(({ from, to }) => from && to)
|
||||
.map(({ from, to, color, exitAfter, enterTime, onlyDirectTo }) => {
|
||||
const length = distance(from, to) || 1;
|
||||
const r1 = 50;
|
||||
const nx1 = ((to.x - from.x) / length) * r1;
|
||||
const ny1 = ((to.y - from.y) / length) * r1;
|
||||
const r2 = 60;
|
||||
const nx2 = ((to.x - from.x) / length) * r2;
|
||||
const ny2 = ((to.y - from.y) / length) * r2;
|
||||
const r3 = 75;
|
||||
const nx3 = ((to.x - from.x) / length) * r3;
|
||||
const ny3 = ((to.y - from.y) / length) * r3;
|
||||
const r4 = 80;
|
||||
const nx4 = ((to.x - from.x) / length) * r4;
|
||||
const ny4 = ((to.y - from.y) / length) * r4;
|
||||
setPos(state.name, 'x', state.x = this.startX + dx);
|
||||
setPos(state.name, 'y', state.y = this.startY + dy);
|
||||
this.updateArrows();
|
||||
}
|
||||
logPositions() {
|
||||
const positions = fromPairs(this.states.map(({ name, x, y }) => [name, { x, y }]));
|
||||
console.log(JSON.stringify(positions).replace(/"/g, `'`).replace(/},/g, '},\n'));
|
||||
}
|
||||
private updateArrows() {
|
||||
this.times = [];
|
||||
this.arrows = flatten(this.states.map(s => s.state.from.map(f => ({
|
||||
to: s,
|
||||
from: this.findState(f.state),
|
||||
color: f.exitAfter === 0 ? (f.keepTime ? 'orange' : 'red') : 'lime',
|
||||
exitAfter: f.exitAfter,
|
||||
enterTime: f.enterTime,
|
||||
onlyDirectTo: f.onlyDirectTo,
|
||||
}))))
|
||||
.filter(({ from, to }) => from && to)
|
||||
.map(({ from, to, color, exitAfter, enterTime, onlyDirectTo }) => {
|
||||
const length = distance(from, to) || 1;
|
||||
const r1 = 50;
|
||||
const nx1 = ((to.x - from.x) / length) * r1;
|
||||
const ny1 = ((to.y - from.y) / length) * r1;
|
||||
const r2 = 60;
|
||||
const nx2 = ((to.x - from.x) / length) * r2;
|
||||
const ny2 = ((to.y - from.y) / length) * r2;
|
||||
const r3 = 75;
|
||||
const nx3 = ((to.x - from.x) / length) * r3;
|
||||
const ny3 = ((to.y - from.y) / length) * r3;
|
||||
const r4 = 80;
|
||||
const nx4 = ((to.x - from.x) / length) * r4;
|
||||
const ny4 = ((to.y - from.y) / length) * r4;
|
||||
|
||||
const fromX = from.x + nx1;
|
||||
const fromY = from.y + ny1;
|
||||
const fromX = from.x + nx1;
|
||||
const fromY = from.y + ny1;
|
||||
|
||||
if (exitAfter) {
|
||||
this.times.push({ x: fromX, y: fromY, color, text: exitAfter.toFixed(1) });
|
||||
}
|
||||
if (exitAfter) {
|
||||
this.times.push({ x: fromX, y: fromY, color, text: exitAfter.toFixed(1) });
|
||||
}
|
||||
|
||||
if (enterTime) {
|
||||
this.times.push({ x: to.x - nx3, y: to.y - ny3, color, text: enterTime.toFixed(1) });
|
||||
}
|
||||
if (enterTime) {
|
||||
this.times.push({ x: to.x - nx3, y: to.y - ny3, color, text: enterTime.toFixed(1) });
|
||||
}
|
||||
|
||||
if (onlyDirectTo) {
|
||||
this.times.push({
|
||||
x: from.x + nx4, y: from.y + ny4, color, text: '?', title: `only directly to: ${onlyDirectTo.name}`
|
||||
});
|
||||
}
|
||||
if (onlyDirectTo) {
|
||||
this.times.push({
|
||||
x: from.x + nx4, y: from.y + ny4, color, text: '?', title: `only directly to: ${onlyDirectTo.name}`
|
||||
});
|
||||
}
|
||||
|
||||
return { path: `M ${fromX} ${fromY} L ${to.x - nx2} ${to.y - ny2}`, color };
|
||||
});
|
||||
}
|
||||
private findState(state: AnimatorState<any>) {
|
||||
return this.states.find(s => s.state === state)!;
|
||||
}
|
||||
return { path: `M ${fromX} ${fromY} L ${to.x - nx2} ${to.y - ny2}`, color };
|
||||
});
|
||||
}
|
||||
private findState(state: AnimatorState<any>) {
|
||||
return this.states.find(s => s.state === state)!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,201 +43,201 @@ tails.forEach((t, i) => t ? t[0].label = labels[i] : undefined);
|
||||
const colors = Object.values(colorNames);
|
||||
|
||||
@Component({
|
||||
selector: 'tools-ui',
|
||||
templateUrl: 'tools-ui.pug',
|
||||
selector: 'tools-ui',
|
||||
templateUrl: 'tools-ui.pug',
|
||||
})
|
||||
export class ToolsUI implements OnInit, OnDestroy {
|
||||
readonly homeIcon = faHome;
|
||||
readonly starIcon = faStar;
|
||||
readonly heartIcon = faHeart;
|
||||
readonly lockIcon = faLock;
|
||||
isHidden = isHidden;
|
||||
isIgnored = isIgnored;
|
||||
focusTrap = true;
|
||||
tails = tails;
|
||||
cmSize = CM_SIZE;
|
||||
pony = offlinePonyInfo;
|
||||
customOutlines = false;
|
||||
pal = offlinePonyPal;
|
||||
color = 'cornflowerblue';
|
||||
checked = true;
|
||||
radio = 'a';
|
||||
slider = 50;
|
||||
sprite = sprites.tails[0]![1]![0];
|
||||
fills = ['ff0000', '00ff00'];
|
||||
outlines = ['990000', '009900'];
|
||||
spriteActive = false;
|
||||
selected = offlinePony;
|
||||
timeout = fromNow(1000 * 3600 * 10).toISOString();
|
||||
autoCloseDropdown: any = true;
|
||||
spamChatInterval: any;
|
||||
initialized = false;
|
||||
customChecked = false;
|
||||
actionBarEditable = true;
|
||||
tags = ['', ...getAllTags().map(t => t.id)];
|
||||
animationFrame: any;
|
||||
virtualItems = times(1000, i => ({ value: i, name: `This is item ${i}`, color: colors[i % colors.length] }));
|
||||
virtualItems2 = [{ name: 'An item 0' }];
|
||||
constructor(
|
||||
private game: PonyTownGame,
|
||||
private zone: NgZone,
|
||||
public settings: SettingsService,
|
||||
private modalService: BsModalService,
|
||||
private model: Model,
|
||||
) {
|
||||
this.selected.name = 'Offline Pony';
|
||||
this.selected.site = {
|
||||
id: '',
|
||||
name: 'Offline Pony (official)',
|
||||
provider: 'twitter',
|
||||
url: 'https://twitter.com/offlinepony',
|
||||
};
|
||||
this.selected.tag = 'dev';
|
||||
this.selected.modInfo = {
|
||||
account: 'offline-pony [abc]',
|
||||
country: 'PL',
|
||||
counters: { swears: 5 },
|
||||
age: 12,
|
||||
};
|
||||
readonly homeIcon = faHome;
|
||||
readonly starIcon = faStar;
|
||||
readonly heartIcon = faHeart;
|
||||
readonly lockIcon = faLock;
|
||||
isHidden = isHidden;
|
||||
isIgnored = isIgnored;
|
||||
focusTrap = true;
|
||||
tails = tails;
|
||||
cmSize = CM_SIZE;
|
||||
pony = offlinePonyInfo;
|
||||
customOutlines = false;
|
||||
pal = offlinePonyPal;
|
||||
color = 'cornflowerblue';
|
||||
checked = true;
|
||||
radio = 'a';
|
||||
slider = 50;
|
||||
sprite = sprites.tails[0]![1]![0];
|
||||
fills = ['ff0000', '00ff00'];
|
||||
outlines = ['990000', '009900'];
|
||||
spriteActive = false;
|
||||
selected = offlinePony;
|
||||
timeout = fromNow(1000 * 3600 * 10).toISOString();
|
||||
autoCloseDropdown: any = true;
|
||||
spamChatInterval: any;
|
||||
initialized = false;
|
||||
customChecked = false;
|
||||
actionBarEditable = true;
|
||||
tags = ['', ...getAllTags().map(t => t.id)];
|
||||
animationFrame: any;
|
||||
virtualItems = times(1000, i => ({ value: i, name: `This is item ${i}`, color: colors[i % colors.length] }));
|
||||
virtualItems2 = [{ name: 'An item 0' }];
|
||||
constructor(
|
||||
private game: PonyTownGame,
|
||||
private zone: NgZone,
|
||||
public settings: SettingsService,
|
||||
private modalService: BsModalService,
|
||||
private model: Model,
|
||||
) {
|
||||
this.selected.name = 'Offline Pony';
|
||||
this.selected.site = {
|
||||
id: '',
|
||||
name: 'Offline Pony (official)',
|
||||
provider: 'twitter',
|
||||
url: 'https://twitter.com/offlinepony',
|
||||
};
|
||||
this.selected.tag = 'dev';
|
||||
this.selected.modInfo = {
|
||||
account: 'offline-pony [abc]',
|
||||
country: 'PL',
|
||||
counters: { swears: 5 },
|
||||
age: 12,
|
||||
};
|
||||
|
||||
game.player = {
|
||||
id: 123,
|
||||
name: 'Player pony',
|
||||
} as any;
|
||||
game.party = {
|
||||
leaderId: 0,
|
||||
members: [
|
||||
{ id: 1, leader: true, offline: false, pending: false, pony: offlinePony, self: false },
|
||||
{ id: 2, leader: false, offline: true, pending: false, pony: supporterPony, self: false },
|
||||
{ id: 3, leader: false, offline: false, pending: true, pony: pendingPony, self: false },
|
||||
],
|
||||
};
|
||||
game.onClock.next('00:00');
|
||||
game.failedFBO = true;
|
||||
game.send = <T>(action: (server: any) => T) => action({
|
||||
action() { },
|
||||
select() { },
|
||||
say() { },
|
||||
expression() { },
|
||||
getInvites: () => Promise.resolve([
|
||||
{ id: 'a', info: OFFLINE_PONY, name: 'Offline Pony', active: true },
|
||||
{ id: 'b', info: OFFLINE_PONY, name: 'Fuzzy', active: true },
|
||||
{ id: 'c', info: OFFLINE_PONY, name: 'Meno', active: true },
|
||||
{ id: 'd', info: OFFLINE_PONY, name: 'Offline Pony', active: true },
|
||||
{ id: 'e', info: OFFLINE_PONY, name: 'Fuzzy', active: true },
|
||||
{ id: 'f', info: OFFLINE_PONY, name: 'Meno', active: false },
|
||||
{ id: 'g', info: OFFLINE_PONY, name: 'Offline Pony', active: false },
|
||||
{ id: 'h', info: OFFLINE_PONY, name: 'Fuzzy', active: false },
|
||||
{ id: 'i', info: OFFLINE_PONY, name: 'Meno', active: false },
|
||||
{ id: 'j', info: OFFLINE_PONY, name: 'Meno', active: false },
|
||||
]),
|
||||
} as any);
|
||||
}
|
||||
ngOnInit() {
|
||||
initFeatureFlags({});
|
||||
game.player = {
|
||||
id: 123,
|
||||
name: 'Player pony',
|
||||
} as any;
|
||||
game.party = {
|
||||
leaderId: 0,
|
||||
members: [
|
||||
{ id: 1, leader: true, offline: false, pending: false, pony: offlinePony, self: false },
|
||||
{ id: 2, leader: false, offline: true, pending: false, pony: supporterPony, self: false },
|
||||
{ id: 3, leader: false, offline: false, pending: true, pony: pendingPony, self: false },
|
||||
],
|
||||
};
|
||||
game.onClock.next('00:00');
|
||||
game.failedFBO = true;
|
||||
game.send = <T>(action: (server: any) => T) => action({
|
||||
action() { },
|
||||
select() { },
|
||||
say() { },
|
||||
expression() { },
|
||||
getInvites: () => Promise.resolve([
|
||||
{ id: 'a', info: OFFLINE_PONY, name: 'Offline Pony', active: true },
|
||||
{ id: 'b', info: OFFLINE_PONY, name: 'Fuzzy', active: true },
|
||||
{ id: 'c', info: OFFLINE_PONY, name: 'Meno', active: true },
|
||||
{ id: 'd', info: OFFLINE_PONY, name: 'Offline Pony', active: true },
|
||||
{ id: 'e', info: OFFLINE_PONY, name: 'Fuzzy', active: true },
|
||||
{ id: 'f', info: OFFLINE_PONY, name: 'Meno', active: false },
|
||||
{ id: 'g', info: OFFLINE_PONY, name: 'Offline Pony', active: false },
|
||||
{ id: 'h', info: OFFLINE_PONY, name: 'Fuzzy', active: false },
|
||||
{ id: 'i', info: OFFLINE_PONY, name: 'Meno', active: false },
|
||||
{ id: 'j', info: OFFLINE_PONY, name: 'Meno', active: false },
|
||||
]),
|
||||
} as any);
|
||||
}
|
||||
ngOnInit() {
|
||||
initFeatureFlags({});
|
||||
|
||||
return loadAndInitSpriteSheets()
|
||||
.then(() => {
|
||||
initializeToys(mockPaletteManager);
|
||||
this.initialized = true;
|
||||
this.model.loading = true;
|
||||
this.zone.runOutsideAngular(() => this.update());
|
||||
});
|
||||
}
|
||||
ngOnDestroy() {
|
||||
cancelAnimationFrame(this.animationFrame);
|
||||
}
|
||||
get baseHairColor() {
|
||||
return getBaseFill(this.pony.mane);
|
||||
}
|
||||
get isFriend() {
|
||||
return isFriend(this.selected);
|
||||
}
|
||||
set isFriend(value) {
|
||||
this.selected.playerState = setFlag(this.selected.playerState, EntityPlayerState.Friend, value);
|
||||
}
|
||||
update() {
|
||||
this.animationFrame = requestAnimationFrame(() => this.update());
|
||||
redrawActionButtons(this.game.actionsChanged);
|
||||
this.game.actionsChanged = false;
|
||||
this.game.onFrame.next();
|
||||
}
|
||||
changed() {
|
||||
syncLockedPonyInfo(this.pony);
|
||||
}
|
||||
toggleIgnored(entity: Entity) {
|
||||
entity.playerState = setFlag(entity.playerState, EntityPlayerState.Ignored, !isIgnored(entity));
|
||||
}
|
||||
toggleHidden(entity: Entity) {
|
||||
entity.playerState = setFlag(entity.playerState, EntityPlayerState.Hidden, !isHidden(entity));
|
||||
}
|
||||
spamChat(chatlog: ChatLog) {
|
||||
if (this.spamChatInterval) {
|
||||
clearInterval(this.spamChatInterval);
|
||||
this.spamChatInterval = 0;
|
||||
} else {
|
||||
this.spamChatInterval = 1;
|
||||
this.zone.runOutsideAngular(() => this.spamChatInterval = setInterval(() => {
|
||||
chatlog.addMessage({
|
||||
id: 0,
|
||||
crc: undefined,
|
||||
name: randomString(random(1, 20)),
|
||||
message: randomString(random(1, 40)),
|
||||
type: MessageType.Chat
|
||||
});
|
||||
}, 50));
|
||||
}
|
||||
}
|
||||
get isPartyLeader() {
|
||||
return isPartyLeader(this.game);
|
||||
}
|
||||
set isPartyLeader(value: boolean) {
|
||||
if (value) {
|
||||
this.game.party!.leaderId = this.game.player!.id;
|
||||
} else {
|
||||
this.game.party!.leaderId = 1;
|
||||
}
|
||||
}
|
||||
get chatlogOpacity() {
|
||||
return this.settings.account.chatlogOpacity || DEFAULT_CHATLOG_OPACITY;
|
||||
}
|
||||
set chatlogOpacity(value: number) {
|
||||
this.settings.account.chatlogOpacity = value;
|
||||
}
|
||||
addMessage(chatlog: ChatLog, message: string) {
|
||||
chatlog.addMessage({ name: 'test name', id: 123, crc: undefined, message, type: MessageType.Chat });
|
||||
}
|
||||
addWhisper(chatlog: ChatLog, message: string) {
|
||||
chatlog.addMessage({ name: 'test name', id: 123, crc: undefined, message, type: MessageType.Whisper });
|
||||
}
|
||||
angle = 45;
|
||||
get angleInRad() {
|
||||
return (this.angle / 180) * Math.PI;
|
||||
}
|
||||
get horizontalTileHeight() {
|
||||
return 32 * Math.sin(this.angleInRad);
|
||||
}
|
||||
get verticalTileHeight() {
|
||||
return 32 * Math.cos(this.angleInRad);
|
||||
}
|
||||
// angle = Math.asin(expectedHorizontalTileHeight / 32) // 0.848062078981481
|
||||
modalRef?: BsModalRef;
|
||||
showModal(template: TemplateRef<any>) {
|
||||
this.modalRef = this.modalService.show(template, {});
|
||||
}
|
||||
saveActions() {
|
||||
if (DEVELOPMENT) {
|
||||
const serialized = serializeActions(this.game.actions);
|
||||
this.game.actions = deserializeActions(serialized);
|
||||
console.log(serialized);
|
||||
}
|
||||
}
|
||||
// actions
|
||||
get expressionActionsColor() {
|
||||
return ACTION_EXPRESSION_BG;
|
||||
}
|
||||
set expressionActionsColor(value) {
|
||||
updateActionColor(colorToCSS(parseColor(value)));
|
||||
this.game.actionsChanged = true;
|
||||
}
|
||||
return loadAndInitSpriteSheets()
|
||||
.then(() => {
|
||||
initializeToys(mockPaletteManager);
|
||||
this.initialized = true;
|
||||
this.model.loading = true;
|
||||
this.zone.runOutsideAngular(() => this.update());
|
||||
});
|
||||
}
|
||||
ngOnDestroy() {
|
||||
cancelAnimationFrame(this.animationFrame);
|
||||
}
|
||||
get baseHairColor() {
|
||||
return getBaseFill(this.pony.mane);
|
||||
}
|
||||
get isFriend() {
|
||||
return isFriend(this.selected);
|
||||
}
|
||||
set isFriend(value) {
|
||||
this.selected.playerState = setFlag(this.selected.playerState, EntityPlayerState.Friend, value);
|
||||
}
|
||||
update() {
|
||||
this.animationFrame = requestAnimationFrame(() => this.update());
|
||||
redrawActionButtons(this.game.actionsChanged);
|
||||
this.game.actionsChanged = false;
|
||||
this.game.onFrame.next();
|
||||
}
|
||||
changed() {
|
||||
syncLockedPonyInfo(this.pony);
|
||||
}
|
||||
toggleIgnored(entity: Entity) {
|
||||
entity.playerState = setFlag(entity.playerState, EntityPlayerState.Ignored, !isIgnored(entity));
|
||||
}
|
||||
toggleHidden(entity: Entity) {
|
||||
entity.playerState = setFlag(entity.playerState, EntityPlayerState.Hidden, !isHidden(entity));
|
||||
}
|
||||
spamChat(chatlog: ChatLog) {
|
||||
if (this.spamChatInterval) {
|
||||
clearInterval(this.spamChatInterval);
|
||||
this.spamChatInterval = 0;
|
||||
} else {
|
||||
this.spamChatInterval = 1;
|
||||
this.zone.runOutsideAngular(() => this.spamChatInterval = setInterval(() => {
|
||||
chatlog.addMessage({
|
||||
id: 0,
|
||||
crc: undefined,
|
||||
name: randomString(random(1, 20)),
|
||||
message: randomString(random(1, 40)),
|
||||
type: MessageType.Chat
|
||||
});
|
||||
}, 50));
|
||||
}
|
||||
}
|
||||
get isPartyLeader() {
|
||||
return isPartyLeader(this.game);
|
||||
}
|
||||
set isPartyLeader(value: boolean) {
|
||||
if (value) {
|
||||
this.game.party!.leaderId = this.game.player!.id;
|
||||
} else {
|
||||
this.game.party!.leaderId = 1;
|
||||
}
|
||||
}
|
||||
get chatlogOpacity() {
|
||||
return this.settings.account.chatlogOpacity || DEFAULT_CHATLOG_OPACITY;
|
||||
}
|
||||
set chatlogOpacity(value: number) {
|
||||
this.settings.account.chatlogOpacity = value;
|
||||
}
|
||||
addMessage(chatlog: ChatLog, message: string) {
|
||||
chatlog.addMessage({ name: 'test name', id: 123, crc: undefined, message, type: MessageType.Chat });
|
||||
}
|
||||
addWhisper(chatlog: ChatLog, message: string) {
|
||||
chatlog.addMessage({ name: 'test name', id: 123, crc: undefined, message, type: MessageType.Whisper });
|
||||
}
|
||||
angle = 45;
|
||||
get angleInRad() {
|
||||
return (this.angle / 180) * Math.PI;
|
||||
}
|
||||
get horizontalTileHeight() {
|
||||
return 32 * Math.sin(this.angleInRad);
|
||||
}
|
||||
get verticalTileHeight() {
|
||||
return 32 * Math.cos(this.angleInRad);
|
||||
}
|
||||
// angle = Math.asin(expectedHorizontalTileHeight / 32) // 0.848062078981481
|
||||
modalRef?: BsModalRef;
|
||||
showModal(template: TemplateRef<any>) {
|
||||
this.modalRef = this.modalService.show(template, {});
|
||||
}
|
||||
saveActions() {
|
||||
if (DEVELOPMENT) {
|
||||
const serialized = serializeActions(this.game.actions);
|
||||
this.game.actions = deserializeActions(serialized);
|
||||
console.log(serialized);
|
||||
}
|
||||
}
|
||||
// actions
|
||||
get expressionActionsColor() {
|
||||
return ACTION_EXPRESSION_BG;
|
||||
}
|
||||
set expressionActionsColor(value) {
|
||||
updateActionColor(colorToCSS(parseColor(value)));
|
||||
this.game.actionsChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,87 +11,87 @@ import { faHome } from '../../../client/icons';
|
||||
import { paletteSpriteSheet } from '../../../generated/sprites';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-variants',
|
||||
templateUrl: 'tools-variants.pug',
|
||||
styleUrls: ['tools-variants.scss'],
|
||||
selector: 'tools-variants',
|
||||
templateUrl: 'tools-variants.pug',
|
||||
styleUrls: ['tools-variants.scss'],
|
||||
})
|
||||
export class ToolsVariants implements OnInit {
|
||||
readonly homeIcon = faHome;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
fields: string[];
|
||||
vertical: keyof PonyInfo = 'backMane';
|
||||
horizontal: keyof PonyInfo = 'mane';
|
||||
coat = 'red';
|
||||
hair = 'gold';
|
||||
justHead = false;
|
||||
scale = 2;
|
||||
private pony: PonyInfo = createDefaultPony();
|
||||
private state: PonyState = defaultPonyState();
|
||||
constructor() {
|
||||
this.fields = Object.keys(this.pony)
|
||||
.filter(key => {
|
||||
const value = (this.pony as any)[key];
|
||||
return value && value.type !== undefined;
|
||||
});
|
||||
}
|
||||
ngOnInit() {
|
||||
loadAndInitSpriteSheets()
|
||||
.then(() => this.redraw());
|
||||
}
|
||||
redraw() {
|
||||
this.draw();
|
||||
}
|
||||
private draw() {
|
||||
this.pony.coatFill = this.coat;
|
||||
this.pony.mane!.fills![0] = this.hair;
|
||||
syncLockedPonyInfo(this.pony);
|
||||
readonly homeIcon = faHome;
|
||||
@ViewChild('canvas', { static: true }) canvas!: ElementRef;
|
||||
fields: string[];
|
||||
vertical: keyof PonyInfo = 'backMane';
|
||||
horizontal: keyof PonyInfo = 'mane';
|
||||
coat = 'red';
|
||||
hair = 'gold';
|
||||
justHead = false;
|
||||
scale = 2;
|
||||
private pony: PonyInfo = createDefaultPony();
|
||||
private state: PonyState = defaultPonyState();
|
||||
constructor() {
|
||||
this.fields = Object.keys(this.pony)
|
||||
.filter(key => {
|
||||
const value = (this.pony as any)[key];
|
||||
return value && value.type !== undefined;
|
||||
});
|
||||
}
|
||||
ngOnInit() {
|
||||
loadAndInitSpriteSheets()
|
||||
.then(() => this.redraw());
|
||||
}
|
||||
redraw() {
|
||||
this.draw();
|
||||
}
|
||||
private draw() {
|
||||
this.pony.coatFill = this.coat;
|
||||
this.pony.mane!.fills![0] = this.hair;
|
||||
syncLockedPonyInfo(this.pony);
|
||||
|
||||
this.fields.forEach(f => (this.pony as any)[f].type = 0);
|
||||
(this.pony as any)[this.vertical].type = 999;
|
||||
(this.pony as any)[this.horizontal].type = 999;
|
||||
this.fields.forEach(f => (this.pony as any)[f].type = 0);
|
||||
(this.pony as any)[this.vertical].type = 999;
|
||||
(this.pony as any)[this.horizontal].type = 999;
|
||||
|
||||
const fixed: any = decompressPony(compressPonyString(this.pony));
|
||||
const maxX = fixed[this.horizontal].type;
|
||||
const maxY = fixed[this.vertical].type;
|
||||
const fixed: any = decompressPony(compressPonyString(this.pony));
|
||||
const maxX = fixed[this.horizontal].type;
|
||||
const maxY = fixed[this.vertical].type;
|
||||
|
||||
const scale = this.scale;
|
||||
const info = toPalette(this.pony);
|
||||
const buffer = createCanvas(80, 80);
|
||||
const batch = new ContextSpriteBatch(buffer);
|
||||
const options = defaultDrawPonyOptions();
|
||||
const scale = this.scale;
|
||||
const info = toPalette(this.pony);
|
||||
const buffer = createCanvas(80, 80);
|
||||
const batch = new ContextSpriteBatch(buffer);
|
||||
const options = defaultDrawPonyOptions();
|
||||
|
||||
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
|
||||
canvas.width = ((maxX + 1) * (this.justHead ? 45 : 60) + 10) * scale;
|
||||
canvas.height = ((maxY + 1) * (this.justHead ? 45 : 60) + 10) * scale;
|
||||
const canvas = this.canvas.nativeElement as HTMLCanvasElement;
|
||||
canvas.width = ((maxX + 1) * (this.justHead ? 45 : 60) + 10) * scale;
|
||||
canvas.height = ((maxY + 1) * (this.justHead ? 45 : 60) + 10) * scale;
|
||||
|
||||
const viewContext = canvas.getContext('2d')!;
|
||||
viewContext.save();
|
||||
disableImageSmoothing(viewContext);
|
||||
viewContext.scale(scale, scale);
|
||||
const viewContext = canvas.getContext('2d')!;
|
||||
viewContext.save();
|
||||
disableImageSmoothing(viewContext);
|
||||
viewContext.scale(scale, scale);
|
||||
|
||||
viewContext.fillStyle = 'LightGreen';
|
||||
viewContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
viewContext.fillStyle = 'LightGreen';
|
||||
viewContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
for (let y = 0; y <= maxY; y++) {
|
||||
(info as any)[this.vertical].type = y;
|
||||
for (let y = 0; y <= maxY; y++) {
|
||||
(info as any)[this.vertical].type = y;
|
||||
|
||||
for (let x = 0; x <= maxX; x++) {
|
||||
batch.start(paletteSpriteSheet, 0);
|
||||
for (let x = 0; x <= maxX; x++) {
|
||||
batch.start(paletteSpriteSheet, 0);
|
||||
|
||||
(info as any)[this.horizontal].type = x;
|
||||
(info as any)[this.horizontal].type = x;
|
||||
|
||||
drawPony(batch, info, this.state, 40, 60, options);
|
||||
drawPony(batch, info, this.state, 40, 60, options);
|
||||
|
||||
batch.end();
|
||||
batch.end();
|
||||
|
||||
if (this.justHead) {
|
||||
viewContext.drawImage(buffer, 0, 0, 55, 45, x * 45 - 10, y * 45, 55, 45);
|
||||
} else {
|
||||
viewContext.drawImage(buffer, x * 60 - 10, y * 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.justHead) {
|
||||
viewContext.drawImage(buffer, 0, 0, 55, 45, x * 45 - 10, y * 45, 55, 45);
|
||||
} else {
|
||||
viewContext.drawImage(buffer, x * 60 - 10, y * 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewContext.restore();
|
||||
}
|
||||
viewContext.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,15 +26,15 @@ import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
|
||||
// } from '../../../generated/shaders';
|
||||
|
||||
@Component({
|
||||
selector: 'tools-webgl',
|
||||
templateUrl: 'tools-webgl.pug',
|
||||
selector: 'tools-webgl',
|
||||
templateUrl: 'tools-webgl.pug',
|
||||
})
|
||||
export class ToolsWebgl implements OnInit {
|
||||
@ViewChild('canvas', { static: true }) canvasElement!: ElementRef;
|
||||
@ViewChild('canvas2', { static: true }) canvasElement2!: ElementRef;
|
||||
ngOnInit() {
|
||||
// testSpriteBatch(this.canvasElement.nativeElement);
|
||||
}
|
||||
@ViewChild('canvas', { static: true }) canvasElement!: ElementRef;
|
||||
@ViewChild('canvas2', { static: true }) canvasElement2!: ElementRef;
|
||||
ngOnInit() {
|
||||
// testSpriteBatch(this.canvasElement.nativeElement);
|
||||
}
|
||||
}
|
||||
|
||||
// export function testLightsShader(canvas: HTMLCanvasElement) {
|
||||
|
||||
@@ -36,64 +36,64 @@ import { ToolsIndex } from './tools-index/tools-index';
|
||||
import { ToolsApp } from './tools';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: '', component: ToolsIndex },
|
||||
{ path: 'sheet', component: ToolsSheet },
|
||||
{ path: 'states', component: ToolsStates },
|
||||
{ path: 'variants', component: ToolsVariants },
|
||||
{ path: 'webgl', component: ToolsWebgl },
|
||||
{ path: 'animation/:id', component: ToolsAnimation },
|
||||
{ path: 'animation', component: ToolsAnimation },
|
||||
{ path: 'chat', component: ToolsChat },
|
||||
{ path: 'expressions', component: ToolsExpressions },
|
||||
{ path: 'entity', component: ToolsEntity },
|
||||
{ path: 'palette', component: ToolsPalette },
|
||||
{ path: 'perf', component: ToolsPerf },
|
||||
{ path: 'regions', component: ToolsRegions },
|
||||
{ path: 'ui', component: ToolsUI },
|
||||
{ path: 'collisions', component: ToolsCollisions },
|
||||
{ path: 'map', component: ToolsMap },
|
||||
{ path: '', component: ToolsIndex },
|
||||
{ path: 'sheet', component: ToolsSheet },
|
||||
{ path: 'states', component: ToolsStates },
|
||||
{ path: 'variants', component: ToolsVariants },
|
||||
{ path: 'webgl', component: ToolsWebgl },
|
||||
{ path: 'animation/:id', component: ToolsAnimation },
|
||||
{ path: 'animation', component: ToolsAnimation },
|
||||
{ path: 'chat', component: ToolsChat },
|
||||
{ path: 'expressions', component: ToolsExpressions },
|
||||
{ path: 'entity', component: ToolsEntity },
|
||||
{ path: 'palette', component: ToolsPalette },
|
||||
{ path: 'perf', component: ToolsPerf },
|
||||
{ path: 'regions', component: ToolsRegions },
|
||||
{ path: 'ui', component: ToolsUI },
|
||||
{ path: 'collisions', component: ToolsCollisions },
|
||||
{ path: 'map', component: ToolsMap },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
RouterModule,
|
||||
FormsModule,
|
||||
HttpClientModule,
|
||||
SharedModule,
|
||||
PopoverModule.forRoot(),
|
||||
TypeaheadModule.forRoot(),
|
||||
ButtonsModule.forRoot(),
|
||||
RouterModule.forRoot(routes),
|
||||
FontAwesomeModule,
|
||||
NoopAnimationsModule,
|
||||
],
|
||||
declarations: [
|
||||
ToolsRange,
|
||||
ToolsFrame,
|
||||
ToolsOffset,
|
||||
ToolsXY,
|
||||
ToolsExpressions,
|
||||
ToolsAnimation,
|
||||
ToolsChat,
|
||||
ToolsVariants,
|
||||
ToolsWebgl,
|
||||
ToolsPalette,
|
||||
ToolsPerf,
|
||||
ToolsRegions,
|
||||
ToolsEntity,
|
||||
ToolsSheet,
|
||||
ToolsStates,
|
||||
ToolsCollisions,
|
||||
ToolsMap,
|
||||
ToolsUI,
|
||||
ToolsIndex,
|
||||
ToolsApp,
|
||||
],
|
||||
providers: [
|
||||
ErrorReporter,
|
||||
],
|
||||
bootstrap: [ToolsApp],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
RouterModule,
|
||||
FormsModule,
|
||||
HttpClientModule,
|
||||
SharedModule,
|
||||
PopoverModule.forRoot(),
|
||||
TypeaheadModule.forRoot(),
|
||||
ButtonsModule.forRoot(),
|
||||
RouterModule.forRoot(routes),
|
||||
FontAwesomeModule,
|
||||
NoopAnimationsModule,
|
||||
],
|
||||
declarations: [
|
||||
ToolsRange,
|
||||
ToolsFrame,
|
||||
ToolsOffset,
|
||||
ToolsXY,
|
||||
ToolsExpressions,
|
||||
ToolsAnimation,
|
||||
ToolsChat,
|
||||
ToolsVariants,
|
||||
ToolsWebgl,
|
||||
ToolsPalette,
|
||||
ToolsPerf,
|
||||
ToolsRegions,
|
||||
ToolsEntity,
|
||||
ToolsSheet,
|
||||
ToolsStates,
|
||||
ToolsCollisions,
|
||||
ToolsMap,
|
||||
ToolsUI,
|
||||
ToolsIndex,
|
||||
ToolsApp,
|
||||
],
|
||||
providers: [
|
||||
ErrorReporter,
|
||||
],
|
||||
bootstrap: [ToolsApp],
|
||||
})
|
||||
export class ToolsAppModule {
|
||||
}
|
||||
|
||||
@@ -3,20 +3,20 @@ import { TooltipConfig } from 'ngx-bootstrap/tooltip';
|
||||
import { PopoverConfig } from 'ngx-bootstrap/popover';
|
||||
|
||||
export function tooltipConfig() {
|
||||
return Object.assign(new TooltipConfig(), { container: 'body' });
|
||||
return Object.assign(new TooltipConfig(), { container: 'body' });
|
||||
}
|
||||
|
||||
export function popoverConfig() {
|
||||
return Object.assign(new PopoverConfig(), { container: 'body' });
|
||||
return Object.assign(new PopoverConfig(), { container: 'body' });
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'pony-town-app',
|
||||
templateUrl: 'tools.pug',
|
||||
providers: [
|
||||
{ provide: TooltipConfig, useFactory: tooltipConfig },
|
||||
{ provide: PopoverConfig, useFactory: popoverConfig },
|
||||
]
|
||||
selector: 'pony-town-app',
|
||||
templateUrl: 'tools.pug',
|
||||
providers: [
|
||||
{ provide: TooltipConfig, useFactory: tooltipConfig },
|
||||
{ provide: PopoverConfig, useFactory: popoverConfig },
|
||||
]
|
||||
})
|
||||
export class ToolsApp {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user